linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-29 21:18 [PATCH 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
@ 2015-08-29 21:18 ` Jes.Sorensen
  2015-08-30  4:42   ` Larry Finger
                     ` (2 more replies)
  0 siblings, 3 replies; 68+ messages in thread
From: Jes.Sorensen @ 2015-08-29 21:18 UTC (permalink / raw)
  To: linux-wireless; +Cc: jes.sorensen, kvalo, Larry.Finger

From: Jes Sorensen <Jes.Sorensen@redhat.com>

This is an alternate driver for a number of Realtek WiFi USB devices,
including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
It was written from scratch utilizing the Linux mac80211 stack.

After spending months cleaning up the vendor provided rtl8723au
driver, which comes with it's own 802.11 stack included, I decided to
rewrite this driver from the bottom up.

Many thanks to Johannes Berg for 802.11 insights and help and Larry
Finger for help with the vendor driver.

The full git log for the development of this driver can be found here:
git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
    branch rtl8723au-mac80211

This driver is still under development, but has proven to be very
stable for me. It currently supports station mode only. It has support
for OFDM and CCK rates, as well as AMPDU. It does lack certain
features found in the staging driver, such as power management and
40MHz channel support. In addition it does not support AD-HOC, AP, and
monitor mode support at this point.

The driver is known to work with the following devices:
Lenovo Yoga (rtl8723au)
TP-Link TL-WN823N (rtl8192cu)
Etekcity 6R (rtl8188cu)
Daffodil LAN03 (rtl8188cu)
Alfa AWUS036NHR (rtl8188ru)

Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
---
 MAINTAINERS                          |    7 +
 drivers/net/wireless/Kconfig         |   32 +
 drivers/net/wireless/Makefile        |    2 +
 drivers/net/wireless/rtl8xxxu.c      | 5829 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/rtl8xxxu.h      |  597 ++++
 drivers/net/wireless/rtl8xxxu_regs.h |  980 ++++++
 6 files changed, 7447 insertions(+)
 create mode 100644 drivers/net/wireless/rtl8xxxu.c
 create mode 100644 drivers/net/wireless/rtl8xxxu.h
 create mode 100644 drivers/net/wireless/rtl8xxxu_regs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b60e2b2..54b03bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8699,6 +8699,13 @@ S:	Maintained
 F:	drivers/net/wireless/rtlwifi/
 F:	drivers/net/wireless/rtlwifi/rtl8192ce/
 
+RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
+M:	Jes Sorensen <Jes.Sorensen@redhat.com>
+L:	linux-wireless@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
+S:	Maintained
+F:	drivers/net/wireless/rtl8xxxu*.[ch]
+
 S3 SAVAGE FRAMEBUFFER DRIVER
 M:	Antonino Daplas <adaplas@gmail.com>
 L:	linux-fbdev@vger.kernel.org
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index a63ab2e..def6cfd 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -243,6 +243,38 @@ config ADM8211
 
 	  Thanks to Infineon-ADMtek for their support of this driver.
 
+config RTL8XXXU
+	tristate "RTL8723AU/RTL8188[CR]U/RTL819[12]CU (mac80211) support"
+	depends on MAC80211 && USB
+	---help---
+	  This is an alternative driver for various Realtek RTL8XXX
+	  parts written to utilize the Linux mac80211 stack.
+	  The driver is known to work with a number of RTL8723AU,
+	  RL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU devices
+
+	  This driver is under development and has a limited feature
+	  set. In particular it does not yet support 40MHz channels
+	  and power management. However it should have a smaller
+	  memory footprint than the vendor drivers and benetifs
+	  from the in kernel mac80211 stack.
+
+	  It can coexist with drivers from drivers/staging/rtl8723au,
+	  drivers/staging/rtl8192u, and drivers/net/wireless/rtlwifi,
+	  but you will need to control which module you wish to load.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called r8xxxu.  If unsure, say N.
+
+config RTL8XXXU_UNTESTED
+	bool "Include support for untested Realtek 8xxx USB devices"
+	depends on RTL8XXXU
+	---help---
+	  This option enables detection of Realtek 8723/8188/8191/8192 WiFi
+	  USB devices which have not been tested directly by the driver
+	  author or reported to be working by third parties.
+
+	  Please report your results!
+
 config MAC80211_HWSIM
 	tristate "Simulated radio testing tool for mac80211"
 	depends on MAC80211
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 6b9e729..593bdef 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -39,6 +39,8 @@ obj-$(CONFIG_LIBERTAS_THINFIRM)	+= libertas_tf/
 
 obj-$(CONFIG_ADM8211)	+= adm8211.o
 
+obj-$(CONFIG_RTL8XXXU)	+= rtl8xxxu.o
+
 obj-$(CONFIG_MWL8K)	+= mwl8k.o
 
 obj-$(CONFIG_IWLWIFI)	+= iwlwifi/
diff --git a/drivers/net/wireless/rtl8xxxu.c b/drivers/net/wireless/rtl8xxxu.c
new file mode 100644
index 0000000..6cc994b
--- /dev/null
+++ b/drivers/net/wireless/rtl8xxxu.c
@@ -0,0 +1,5829 @@
+/*
+ * RTL8XXXU mac80211 USB driver
+ *
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Portions, notably calibration code:
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This driver was written as a replacement for the vendor provided
+ * rtl8723au driver. As the Realtek 8xxx chips are very similar in
+ * their programming interface, I have started adding support for
+ * additional 8xxx chips like the 8192cu, 8188cus, etc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/moduleparam.h>
+#include <net/mac80211.h>
+#include "rtl8xxxu.h"
+#include "rtl8xxxu_regs.h"
+
+#define DRIVER_NAME "rtl8xxxu"
+
+static int rtl8xxxu_debug = 0;
+
+MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>");
+MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin");
+
+module_param_named(debug, rtl8xxxu_debug, int, 0600);
+MODULE_PARM_DESC(debug, "Set debug mask");
+
+#define USB_VENDOR_ID_REALTEK		0x0bda
+/* Minimum IEEE80211_MAX_FRAME_LEN */
+#define RTL_RX_BUFFER_SIZE		IEEE80211_MAX_FRAME_LEN
+
+static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb);
+
+static struct ieee80211_rate rtl8xxxu_rates[] = {
+	{ .bitrate = 10, .hw_value = DESC_RATE_1M, .flags = 0 },
+	{ .bitrate = 20, .hw_value = DESC_RATE_2M, .flags = 0 },
+	{ .bitrate = 55, .hw_value = DESC_RATE_5_5M, .flags = 0 },
+	{ .bitrate = 110, .hw_value = DESC_RATE_11M, .flags = 0 },
+	{ .bitrate = 60, .hw_value = DESC_RATE_6M, .flags = 0 },
+	{ .bitrate = 90, .hw_value = DESC_RATE_9M, .flags = 0 },
+	{ .bitrate = 120, .hw_value = DESC_RATE_12M, .flags = 0 },
+	{ .bitrate = 180, .hw_value = DESC_RATE_18M, .flags = 0 },
+	{ .bitrate = 240, .hw_value = DESC_RATE_24M, .flags = 0 },
+	{ .bitrate = 360, .hw_value = DESC_RATE_36M, .flags = 0 },
+	{ .bitrate = 480, .hw_value = DESC_RATE_48M, .flags = 0 },
+	{ .bitrate = 540, .hw_value = DESC_RATE_54M, .flags = 0 },
+};
+
+static struct ieee80211_channel rtl8xxxu_channels_2g[] = {
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2412,
+	  .hw_value = 1, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2417,
+	  .hw_value = 2, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2422,
+	  .hw_value = 3, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2427,
+	  .hw_value = 4, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2432,
+	  .hw_value = 5, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2437,
+	  .hw_value = 6, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2442,
+	  .hw_value = 7, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2447,
+	  .hw_value = 8, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2452,
+	  .hw_value = 9, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2457,
+	  .hw_value = 10, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2462,
+	  .hw_value = 11, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2467,
+	  .hw_value = 12, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2472,
+	  .hw_value = 13, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2484,
+	  .hw_value = 14, .max_power = 30 }
+};
+
+static struct ieee80211_supported_band rtl8xxxu_supported_band = {
+	.channels = rtl8xxxu_channels_2g,
+	.n_channels = ARRAY_SIZE(rtl8xxxu_channels_2g),
+	.bitrates = rtl8xxxu_rates,
+	.n_bitrates = ARRAY_SIZE(rtl8xxxu_rates),
+};
+
+static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = {
+	{0x420, 0x80}, {0x423, 0x00}, {0x430, 0x00}, {0x431, 0x00},
+	{0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05},
+	{0x436, 0x06}, {0x437, 0x07}, {0x438, 0x00}, {0x439, 0x00},
+	{0x43a, 0x00}, {0x43b, 0x01}, {0x43c, 0x04}, {0x43d, 0x05},
+	{0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01},
+	{0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f},
+	{0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72},
+	{0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x462, 0x08},
+	{0x463, 0x03}, {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff},
+	{0x4cd, 0xff}, {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2},
+	{0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3},
+	{0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4},
+	{0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4},
+	{0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a},
+	{0x515, 0x10}, {0x516, 0x0a}, {0x517, 0x10}, {0x51a, 0x16},
+	{0x524, 0x0f}, {0x525, 0x4f}, {0x546, 0x40}, {0x547, 0x00},
+	{0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, {0x55a, 0x02},
+	{0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a},
+	{0x652, 0x20}, {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e},
+	{0x63f, 0x0e}, {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43},
+	{0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43},
+	{0x70a, 0x65}, {0x70b, 0x87}, {0xffff, 0xff},
+};
+
+static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = {
+	{0x800, 0x80040000}, {0x804, 0x00000003},
+	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+	{0x810, 0x10001331}, {0x814, 0x020c3d10},
+	{0x818, 0x02200385}, {0x81c, 0x00000000},
+	{0x820, 0x01000100}, {0x824, 0x00390004},
+	{0x828, 0x00000000}, {0x82c, 0x00000000},
+	{0x830, 0x00000000}, {0x834, 0x00000000},
+	{0x838, 0x00000000}, {0x83c, 0x00000000},
+	{0x840, 0x00010000}, {0x844, 0x00000000},
+	{0x848, 0x00000000}, {0x84c, 0x00000000},
+	{0x850, 0x00000000}, {0x854, 0x00000000},
+	{0x858, 0x569a569a}, {0x85c, 0x001b25a4},
+	{0x860, 0x66f60110}, {0x864, 0x061f0130},
+	{0x868, 0x00000000}, {0x86c, 0x32323200},
+	{0x870, 0x07000760}, {0x874, 0x22004000},
+	{0x878, 0x00000808}, {0x87c, 0x00000000},
+	{0x880, 0xc0083070}, {0x884, 0x000004d5},
+	{0x888, 0x00000000}, {0x88c, 0xccc000c0},
+	{0x890, 0x00000800}, {0x894, 0xfffffffe},
+	{0x898, 0x40302010}, {0x89c, 0x00706050},
+	{0x900, 0x00000000}, {0x904, 0x00000023},
+	{0x908, 0x00000000}, {0x90c, 0x81121111},
+	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
+	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
+	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
+	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
+	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
+	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
+	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
+	{0xa78, 0x00000900},
+	{0xc00, 0x48071d40}, {0xc04, 0x03a05611},
+	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
+	{0xc10, 0x08800000}, {0xc14, 0x40000100},
+	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
+	{0xc20, 0x00000000}, {0xc24, 0x00000000},
+	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
+	{0xc30, 0x69e9ac44}, {0xc34, 0x469652af},
+	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
+	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
+	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
+	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
+	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
+	{0xc60, 0x00000000}, {0xc64, 0x7112848b},
+	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
+	{0xc70, 0x2c7f000d}, {0xc74, 0x018610db},
+	{0xc78, 0x0000001f}, {0xc7c, 0x00b91612},
+	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
+	{0xc88, 0x40000100}, {0xc8c, 0x20200000},
+	{0xc90, 0x00121820}, {0xc94, 0x00000000},
+	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
+	{0xca0, 0x00000000}, {0xca4, 0x00000080},
+	{0xca8, 0x00000000}, {0xcac, 0x00000000},
+	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
+	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
+	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
+	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
+	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
+	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
+	{0xce0, 0x00222222}, {0xce4, 0x00000000},
+	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
+	{0xd00, 0x00080740}, {0xd04, 0x00020401},
+	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
+	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
+	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
+	{0xd30, 0x00000000}, {0xd34, 0x80608000},
+	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
+	{0xd40, 0x00000000}, {0xd44, 0x00000000},
+	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
+	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
+	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
+	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
+	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
+	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
+	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
+	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
+	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
+	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
+	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
+	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
+	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
+	{0xe5c, 0x28160d05}, {0xe60, 0x00000008},
+	{0xe68, 0x001b25a4}, {0xe6c, 0x631b25a0},
+	{0xe70, 0x631b25a0}, {0xe74, 0x081b25a0},
+	{0xe78, 0x081b25a0}, {0xe7c, 0x081b25a0},
+	{0xe80, 0x081b25a0}, {0xe84, 0x631b25a0},
+	{0xe88, 0x081b25a0}, {0xe8c, 0x631b25a0},
+	{0xed0, 0x631b25a0}, {0xed4, 0x631b25a0},
+	{0xed8, 0x631b25a0}, {0xedc, 0x001b25a0},
+	{0xee0, 0x001b25a0}, {0xeec, 0x6b1b25a0},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8192cu_phy_2t_init_table[] = {
+	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
+	{0x800, 0x80040002}, {0x804, 0x00000003},
+	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+	{0x810, 0x10000330}, {0x814, 0x020c3d10},
+	{0x818, 0x02200385}, {0x81c, 0x00000000},
+	{0x820, 0x01000100}, {0x824, 0x00390004},
+	{0x828, 0x01000100}, {0x82c, 0x00390004},
+	{0x830, 0x27272727}, {0x834, 0x27272727},
+	{0x838, 0x27272727}, {0x83c, 0x27272727},
+	{0x840, 0x00010000}, {0x844, 0x00010000},
+	{0x848, 0x27272727}, {0x84c, 0x27272727},
+	{0x850, 0x00000000}, {0x854, 0x00000000},
+	{0x858, 0x569a569a}, {0x85c, 0x0c1b25a4},
+	{0x860, 0x66e60230}, {0x864, 0x061f0130},
+	{0x868, 0x27272727}, {0x86c, 0x2b2b2b27},
+	{0x870, 0x07000700}, {0x874, 0x22184000},
+	{0x878, 0x08080808}, {0x87c, 0x00000000},
+	{0x880, 0xc0083070}, {0x884, 0x000004d5},
+	{0x888, 0x00000000}, {0x88c, 0xcc0000c0},
+	{0x890, 0x00000800}, {0x894, 0xfffffffe},
+	{0x898, 0x40302010}, {0x89c, 0x00706050},
+	{0x900, 0x00000000}, {0x904, 0x00000023},
+	{0x908, 0x00000000}, {0x90c, 0x81121313},
+	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
+	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
+	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
+	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
+	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
+	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
+	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
+	{0xc00, 0x48071d40}, {0xc04, 0x03a05633},
+	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
+	{0xc10, 0x08800000}, {0xc14, 0x40000100},
+	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
+	{0xc20, 0x00000000}, {0xc24, 0x00000000},
+	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
+	{0xc30, 0x69e9ac44}, {0xc34, 0x469652cf},
+	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
+	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
+	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
+	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
+	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
+	{0xc60, 0x00000000}, {0xc64, 0x5116848b},
+	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
+	{0xc70, 0x2c7f000d}, {0xc74, 0x2186115b},
+	{0xc78, 0x0000001f}, {0xc7c, 0x00b99612},
+	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
+	{0xc88, 0x40000100}, {0xc8c, 0xa0e40000},
+	{0xc90, 0x00121820}, {0xc94, 0x00000000},
+	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
+	{0xca0, 0x00000000}, {0xca4, 0x00000080},
+	{0xca8, 0x00000000}, {0xcac, 0x00000000},
+	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
+	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
+	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
+	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
+	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
+	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
+	{0xce0, 0x00222222}, {0xce4, 0x00000000},
+	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
+	{0xd00, 0x00080740}, {0xd04, 0x00020403},
+	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
+	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
+	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
+	{0xd30, 0x00000000}, {0xd34, 0x80608000},
+	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
+	{0xd40, 0x00000000}, {0xd44, 0x00000000},
+	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
+	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
+	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
+	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
+	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
+	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
+	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
+	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
+	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
+	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
+	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
+	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
+	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
+	{0xe5c, 0x28160d05}, {0xe60, 0x00000010},
+	{0xe68, 0x001b25a4}, {0xe6c, 0x63db25a4},
+	{0xe70, 0x63db25a4}, {0xe74, 0x0c1b25a4},
+	{0xe78, 0x0c1b25a4}, {0xe7c, 0x0c1b25a4},
+	{0xe80, 0x0c1b25a4}, {0xe84, 0x63db25a4},
+	{0xe88, 0x0c1b25a4}, {0xe8c, 0x63db25a4},
+	{0xed0, 0x63db25a4}, {0xed4, 0x63db25a4},
+	{0xed8, 0x63db25a4}, {0xedc, 0x001b25a4},
+	{0xee0, 0x001b25a4}, {0xeec, 0x6fdb25a4},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8188ru_phy_1t_highpa_table[] = {
+	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
+	{0x040, 0x000c0004}, {0x800, 0x80040000},
+	{0x804, 0x00000001}, {0x808, 0x0000fc00},
+	{0x80c, 0x0000000a}, {0x810, 0x10005388},
+	{0x814, 0x020c3d10}, {0x818, 0x02200385},
+	{0x81c, 0x00000000}, {0x820, 0x01000100},
+	{0x824, 0x00390204}, {0x828, 0x00000000},
+	{0x82c, 0x00000000}, {0x830, 0x00000000},
+	{0x834, 0x00000000}, {0x838, 0x00000000},
+	{0x83c, 0x00000000}, {0x840, 0x00010000},
+	{0x844, 0x00000000}, {0x848, 0x00000000},
+	{0x84c, 0x00000000}, {0x850, 0x00000000},
+	{0x854, 0x00000000}, {0x858, 0x569a569a},
+	{0x85c, 0x001b25a4}, {0x860, 0x66e60230},
+	{0x864, 0x061f0130}, {0x868, 0x00000000},
+	{0x86c, 0x20202000}, {0x870, 0x03000300},
+	{0x874, 0x22004000}, {0x878, 0x00000808},
+	{0x87c, 0x00ffc3f1}, {0x880, 0xc0083070},
+	{0x884, 0x000004d5}, {0x888, 0x00000000},
+	{0x88c, 0xccc000c0}, {0x890, 0x00000800},
+	{0x894, 0xfffffffe}, {0x898, 0x40302010},
+	{0x89c, 0x00706050}, {0x900, 0x00000000},
+	{0x904, 0x00000023}, {0x908, 0x00000000},
+	{0x90c, 0x81121111}, {0xa00, 0x00d047c8},
+	{0xa04, 0x80ff000c}, {0xa08, 0x8c838300},
+	{0xa0c, 0x2e68120f}, {0xa10, 0x9500bb78},
+	{0xa14, 0x11144028}, {0xa18, 0x00881117},
+	{0xa1c, 0x89140f00}, {0xa20, 0x15160000},
+	{0xa24, 0x070b0f12}, {0xa28, 0x00000104},
+	{0xa2c, 0x00d30000}, {0xa70, 0x101fbf00},
+	{0xa74, 0x00000007}, {0xc00, 0x48071d40},
+	{0xc04, 0x03a05611}, {0xc08, 0x000000e4},
+	{0xc0c, 0x6c6c6c6c}, {0xc10, 0x08800000},
+	{0xc14, 0x40000100}, {0xc18, 0x08800000},
+	{0xc1c, 0x40000100}, {0xc20, 0x00000000},
+	{0xc24, 0x00000000}, {0xc28, 0x00000000},
+	{0xc2c, 0x00000000}, {0xc30, 0x69e9ac44},
+	{0xc34, 0x469652cf}, {0xc38, 0x49795994},
+	{0xc3c, 0x0a97971c}, {0xc40, 0x1f7c403f},
+	{0xc44, 0x000100b7}, {0xc48, 0xec020107},
+	{0xc4c, 0x007f037f}, {0xc50, 0x6954342e},
+	{0xc54, 0x43bc0094}, {0xc58, 0x6954342f},
+	{0xc5c, 0x433c0094}, {0xc60, 0x00000000},
+	{0xc64, 0x5116848b}, {0xc68, 0x47c00bff},
+	{0xc6c, 0x00000036}, {0xc70, 0x2c46000d},
+	{0xc74, 0x018610db}, {0xc78, 0x0000001f},
+	{0xc7c, 0x00b91612}, {0xc80, 0x24000090},
+	{0xc84, 0x20f60000}, {0xc88, 0x24000090},
+	{0xc8c, 0x20200000}, {0xc90, 0x00121820},
+	{0xc94, 0x00000000}, {0xc98, 0x00121820},
+	{0xc9c, 0x00007f7f}, {0xca0, 0x00000000},
+	{0xca4, 0x00000080}, {0xca8, 0x00000000},
+	{0xcac, 0x00000000}, {0xcb0, 0x00000000},
+	{0xcb4, 0x00000000}, {0xcb8, 0x00000000},
+	{0xcbc, 0x28000000}, {0xcc0, 0x00000000},
+	{0xcc4, 0x00000000}, {0xcc8, 0x00000000},
+	{0xccc, 0x00000000}, {0xcd0, 0x00000000},
+	{0xcd4, 0x00000000}, {0xcd8, 0x64b22427},
+	{0xcdc, 0x00766932}, {0xce0, 0x00222222},
+	{0xce4, 0x00000000}, {0xce8, 0x37644302},
+	{0xcec, 0x2f97d40c}, {0xd00, 0x00080740},
+	{0xd04, 0x00020401}, {0xd08, 0x0000907f},
+	{0xd0c, 0x20010201}, {0xd10, 0xa0633333},
+	{0xd14, 0x3333bc43}, {0xd18, 0x7a8f5b6b},
+	{0xd2c, 0xcc979975}, {0xd30, 0x00000000},
+	{0xd34, 0x80608000}, {0xd38, 0x00000000},
+	{0xd3c, 0x00027293}, {0xd40, 0x00000000},
+	{0xd44, 0x00000000}, {0xd48, 0x00000000},
+	{0xd4c, 0x00000000}, {0xd50, 0x6437140a},
+	{0xd54, 0x00000000}, {0xd58, 0x00000000},
+	{0xd5c, 0x30032064}, {0xd60, 0x4653de68},
+	{0xd64, 0x04518a3c}, {0xd68, 0x00002101},
+	{0xd6c, 0x2a201c16}, {0xd70, 0x1812362e},
+	{0xd74, 0x322c2220}, {0xd78, 0x000e3c24},
+	{0xe00, 0x24242424}, {0xe04, 0x24242424},
+	{0xe08, 0x03902024}, {0xe10, 0x24242424},
+	{0xe14, 0x24242424}, {0xe18, 0x24242424},
+	{0xe1c, 0x24242424}, {0xe28, 0x00000000},
+	{0xe30, 0x1000dc1f}, {0xe34, 0x10008c1f},
+	{0xe38, 0x02140102}, {0xe3c, 0x681604c2},
+	{0xe40, 0x01007c00}, {0xe44, 0x01004800},
+	{0xe48, 0xfb000000}, {0xe4c, 0x000028d1},
+	{0xe50, 0x1000dc1f}, {0xe54, 0x10008c1f},
+	{0xe58, 0x02140102}, {0xe5c, 0x28160d05},
+	{0xe60, 0x00000008}, {0xe68, 0x001b25a4},
+	{0xe6c, 0x631b25a0}, {0xe70, 0x631b25a0},
+	{0xe74, 0x081b25a0}, {0xe78, 0x081b25a0},
+	{0xe7c, 0x081b25a0}, {0xe80, 0x081b25a0},
+	{0xe84, 0x631b25a0}, {0xe88, 0x081b25a0},
+	{0xe8c, 0x631b25a0}, {0xed0, 0x631b25a0},
+	{0xed4, 0x631b25a0}, {0xed8, 0x631b25a0},
+	{0xedc, 0x001b25a0}, {0xee0, 0x001b25a0},
+	{0xeec, 0x6b1b25a0}, {0xee8, 0x31555448},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_standard_table[] = {
+	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
+	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
+	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
+	{0xc78, 0x7a060001}, {0xc78, 0x79070001},
+	{0xc78, 0x78080001}, {0xc78, 0x77090001},
+	{0xc78, 0x760a0001}, {0xc78, 0x750b0001},
+	{0xc78, 0x740c0001}, {0xc78, 0x730d0001},
+	{0xc78, 0x720e0001}, {0xc78, 0x710f0001},
+	{0xc78, 0x70100001}, {0xc78, 0x6f110001},
+	{0xc78, 0x6e120001}, {0xc78, 0x6d130001},
+	{0xc78, 0x6c140001}, {0xc78, 0x6b150001},
+	{0xc78, 0x6a160001}, {0xc78, 0x69170001},
+	{0xc78, 0x68180001}, {0xc78, 0x67190001},
+	{0xc78, 0x661a0001}, {0xc78, 0x651b0001},
+	{0xc78, 0x641c0001}, {0xc78, 0x631d0001},
+	{0xc78, 0x621e0001}, {0xc78, 0x611f0001},
+	{0xc78, 0x60200001}, {0xc78, 0x49210001},
+	{0xc78, 0x48220001}, {0xc78, 0x47230001},
+	{0xc78, 0x46240001}, {0xc78, 0x45250001},
+	{0xc78, 0x44260001}, {0xc78, 0x43270001},
+	{0xc78, 0x42280001}, {0xc78, 0x41290001},
+	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
+	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
+	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
+	{0xc78, 0x21300001}, {0xc78, 0x20310001},
+	{0xc78, 0x06320001}, {0xc78, 0x05330001},
+	{0xc78, 0x04340001}, {0xc78, 0x03350001},
+	{0xc78, 0x02360001}, {0xc78, 0x01370001},
+	{0xc78, 0x00380001}, {0xc78, 0x00390001},
+	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
+	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
+	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
+	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
+	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
+	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
+	{0xc78, 0x7a460001}, {0xc78, 0x79470001},
+	{0xc78, 0x78480001}, {0xc78, 0x77490001},
+	{0xc78, 0x764a0001}, {0xc78, 0x754b0001},
+	{0xc78, 0x744c0001}, {0xc78, 0x734d0001},
+	{0xc78, 0x724e0001}, {0xc78, 0x714f0001},
+	{0xc78, 0x70500001}, {0xc78, 0x6f510001},
+	{0xc78, 0x6e520001}, {0xc78, 0x6d530001},
+	{0xc78, 0x6c540001}, {0xc78, 0x6b550001},
+	{0xc78, 0x6a560001}, {0xc78, 0x69570001},
+	{0xc78, 0x68580001}, {0xc78, 0x67590001},
+	{0xc78, 0x665a0001}, {0xc78, 0x655b0001},
+	{0xc78, 0x645c0001}, {0xc78, 0x635d0001},
+	{0xc78, 0x625e0001}, {0xc78, 0x615f0001},
+	{0xc78, 0x60600001}, {0xc78, 0x49610001},
+	{0xc78, 0x48620001}, {0xc78, 0x47630001},
+	{0xc78, 0x46640001}, {0xc78, 0x45650001},
+	{0xc78, 0x44660001}, {0xc78, 0x43670001},
+	{0xc78, 0x42680001}, {0xc78, 0x41690001},
+	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
+	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
+	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
+	{0xc78, 0x21700001}, {0xc78, 0x20710001},
+	{0xc78, 0x06720001}, {0xc78, 0x05730001},
+	{0xc78, 0x04740001}, {0xc78, 0x03750001},
+	{0xc78, 0x02760001}, {0xc78, 0x01770001},
+	{0xc78, 0x00780001}, {0xc78, 0x00790001},
+	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
+	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
+	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
+	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
+	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
+	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
+	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
+	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
+	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
+	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
+	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
+	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
+	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
+	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
+	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
+	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
+	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
+	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
+	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
+	{0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_highpa_table[] = {
+	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
+	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
+	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
+	{0xc78, 0x7b060001}, {0xc78, 0x7b070001},
+	{0xc78, 0x7b080001}, {0xc78, 0x7a090001},
+	{0xc78, 0x790a0001}, {0xc78, 0x780b0001},
+	{0xc78, 0x770c0001}, {0xc78, 0x760d0001},
+	{0xc78, 0x750e0001}, {0xc78, 0x740f0001},
+	{0xc78, 0x73100001}, {0xc78, 0x72110001},
+	{0xc78, 0x71120001}, {0xc78, 0x70130001},
+	{0xc78, 0x6f140001}, {0xc78, 0x6e150001},
+	{0xc78, 0x6d160001}, {0xc78, 0x6c170001},
+	{0xc78, 0x6b180001}, {0xc78, 0x6a190001},
+	{0xc78, 0x691a0001}, {0xc78, 0x681b0001},
+	{0xc78, 0x671c0001}, {0xc78, 0x661d0001},
+	{0xc78, 0x651e0001}, {0xc78, 0x641f0001},
+	{0xc78, 0x63200001}, {0xc78, 0x62210001},
+	{0xc78, 0x61220001}, {0xc78, 0x60230001},
+	{0xc78, 0x46240001}, {0xc78, 0x45250001},
+	{0xc78, 0x44260001}, {0xc78, 0x43270001},
+	{0xc78, 0x42280001}, {0xc78, 0x41290001},
+	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
+	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
+	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
+	{0xc78, 0x21300001}, {0xc78, 0x20310001},
+	{0xc78, 0x06320001}, {0xc78, 0x05330001},
+	{0xc78, 0x04340001}, {0xc78, 0x03350001},
+	{0xc78, 0x02360001}, {0xc78, 0x01370001},
+	{0xc78, 0x00380001}, {0xc78, 0x00390001},
+	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
+	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
+	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
+	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
+	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
+	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
+	{0xc78, 0x7b460001}, {0xc78, 0x7b470001},
+	{0xc78, 0x7b480001}, {0xc78, 0x7a490001},
+	{0xc78, 0x794a0001}, {0xc78, 0x784b0001},
+	{0xc78, 0x774c0001}, {0xc78, 0x764d0001},
+	{0xc78, 0x754e0001}, {0xc78, 0x744f0001},
+	{0xc78, 0x73500001}, {0xc78, 0x72510001},
+	{0xc78, 0x71520001}, {0xc78, 0x70530001},
+	{0xc78, 0x6f540001}, {0xc78, 0x6e550001},
+	{0xc78, 0x6d560001}, {0xc78, 0x6c570001},
+	{0xc78, 0x6b580001}, {0xc78, 0x6a590001},
+	{0xc78, 0x695a0001}, {0xc78, 0x685b0001},
+	{0xc78, 0x675c0001}, {0xc78, 0x665d0001},
+	{0xc78, 0x655e0001}, {0xc78, 0x645f0001},
+	{0xc78, 0x63600001}, {0xc78, 0x62610001},
+	{0xc78, 0x61620001}, {0xc78, 0x60630001},
+	{0xc78, 0x46640001}, {0xc78, 0x45650001},
+	{0xc78, 0x44660001}, {0xc78, 0x43670001},
+	{0xc78, 0x42680001}, {0xc78, 0x41690001},
+	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
+	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
+	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
+	{0xc78, 0x21700001}, {0xc78, 0x20710001},
+	{0xc78, 0x06720001}, {0xc78, 0x05730001},
+	{0xc78, 0x04740001}, {0xc78, 0x03750001},
+	{0xc78, 0x02760001}, {0xc78, 0x01770001},
+	{0xc78, 0x00780001}, {0xc78, 0x00790001},
+	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
+	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
+	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
+	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
+	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
+	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
+	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
+	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
+	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
+	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
+	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
+	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
+	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
+	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
+	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
+	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
+	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
+	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
+	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
+	{0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00039c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001a3f1}, {0x0b, 0x00014787},
+	{0x0c, 0x000896fe}, {0x0d, 0x0000e02c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00030355},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0000024f},
+	{0x1f, 0x00000000}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x00057730},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f474},
+	{0x15, 0x0004f477}, {0x15, 0x0008f455},
+	{0x15, 0x000cf455}, {0x16, 0x00000339},
+	{0x16, 0x00040339}, {0x16, 0x00080339},
+	{0x16, 0x000c0366}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00000003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00000247}, {0x1f, 0x00000000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00010255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f424},
+	{0x15, 0x0004f424}, {0x15, 0x0008f424},
+	{0x15, 0x000cf424}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radiob_2t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287af}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x00014297},
+	{0x13, 0x00010295}, {0x13, 0x0000c298},
+	{0x13, 0x0000819c}, {0x13, 0x000040a8},
+	{0x13, 0x0000001c}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f424},
+	{0x15, 0x0004f424}, {0x15, 0x0008f424},
+	{0x15, 0x000cf424}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radioa_1t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00010255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f405},
+	{0x15, 0x0004f405}, {0x15, 0x0008f405},
+	{0x15, 0x000cf405}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb0}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e529},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00000255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x0000083c},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000977c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x000d8000}, {0x12, 0x00090000},
+	{0x12, 0x00051000}, {0x12, 0x00012000},
+	{0x13, 0x00028fb4}, {0x13, 0x00024fa8},
+	{0x13, 0x000207a4}, {0x13, 0x0001c3b0},
+	{0x13, 0x000183a4}, {0x13, 0x00014398},
+	{0x13, 0x000101a4}, {0x13, 0x0000c198},
+	{0x13, 0x000080a4}, {0x13, 0x00004098},
+	{0x13, 0x00000000}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f405},
+	{0x15, 0x0004f405}, {0x15, 0x0008f405},
+	{0x15, 0x000cf405}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = {
+	{	/* RF_A */
+		.hssiparm1 = REG_FPGA0_XA_HSSI_PARM1,
+		.hssiparm2 = REG_FPGA0_XA_HSSI_PARM2,
+		.lssiparm = REG_FPGA0_XA_LSSI_PARM,
+		.hspiread = REG_HSPI_XA_READBACK,
+		.lssiread = REG_FPGA0_XA_LSSI_READBACK,
+		.rf_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL,
+	},
+	{	/* RF_B */
+		.hssiparm1 = REG_FPGA0_XB_HSSI_PARM1,
+		.hssiparm2 = REG_FPGA0_XB_HSSI_PARM2,
+		.lssiparm = REG_FPGA0_XB_LSSI_PARM,
+		.hspiread = REG_HSPI_XB_READBACK,
+		.lssiread = REG_FPGA0_XB_LSSI_READBACK,
+		.rf_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL,
+	},
+};
+
+static const u32 rtl8723au_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = {
+	REG_OFDM0_XA_RX_IQ_IMBALANCE,
+	REG_OFDM0_XB_RX_IQ_IMBALANCE,
+	REG_OFDM0_ENERGY_CCA_THRES,
+	REG_OFDM0_AGCR_SSI_TABLE,
+	REG_OFDM0_XA_TX_IQ_IMBALANCE,
+	REG_OFDM0_XB_TX_IQ_IMBALANCE,
+	REG_OFDM0_XC_TX_AFE,
+	REG_OFDM0_XD_TX_AFE,
+	REG_OFDM0_RX_IQ_EXT_ANTA
+};
+
+static u8 rtl8xxxu_read8(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u8 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = priv->usb_buf.val8;
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)   = 0x%02x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static u16 rtl8xxxu_read16(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u16 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = le16_to_cpu(priv->usb_buf.val16);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)  = 0x%04x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static u32 rtl8xxxu_read32(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u32 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = le32_to_cpu(priv->usb_buf.val32);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)  = 0x%08x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static int rtl8xxxu_write8(struct rtl8xxxu_priv *priv, u16 addr, u8 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val8 = val;
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%02x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int rtl8xxxu_write16(struct rtl8xxxu_priv *priv, u16 addr, u16 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val16 = cpu_to_le16(val);
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%04x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int rtl8xxxu_write32(struct rtl8xxxu_priv *priv, u16 addr, u32 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val32 = cpu_to_le32(val);
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%08x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int
+rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = %p, len 0x%02x\n",
+			 __func__, addr, buf, len);
+	return ret;
+}
+
+static int
+rtl8xxxu_slow_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
+{
+	u32 blocksize = sizeof(u32);
+	u32 *buf4 = (u32 *)buf;
+	int i, offset, count, remainder;
+
+	count = len / blocksize;
+	remainder = len % blocksize;
+
+	for (i = 0; i < count; i++) {
+		offset = i * blocksize;
+		rtl8xxxu_write32(priv, (REG_FW_START_ADDRESS + offset),
+				 buf4[i]);
+	}
+
+	if (remainder) {
+		offset = count * blocksize;
+		buf += offset;
+		for (i = 0; i < remainder; i++) {
+			rtl8xxxu_write8(priv, (REG_FW_START_ADDRESS +
+					       offset + i), *(buf + i));
+		}
+	}
+
+	return len;
+}
+
+static u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv,
+			       enum rtl8xxxu_rfpath path, u8 reg)
+{
+	u32 hssia, val32, retval;
+
+	hssia = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+	if (path != RF_A)
+		val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm2);
+	else
+		val32 = hssia;
+
+	val32 &= ~FPGA0_HSSI_PARM2_ADDR_MASK;
+	val32 |= (reg << FPGA0_HSSI_PARM2_ADDR_SHIFT);
+	val32 |= FPGA0_HSSI_PARM2_EDGE_READ;
+	hssia &= ~FPGA0_HSSI_PARM2_EDGE_READ;
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
+
+	udelay(10);
+
+	rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].hssiparm2, val32);
+	udelay(100);
+
+	hssia |= FPGA0_HSSI_PARM2_EDGE_READ;
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
+	udelay(10);
+
+	val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm1);
+	if (val32 & FPGA0_HSSI_PARM1_PI)
+		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hspiread);
+	else
+		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].lssiread);
+
+	retval &= 0xfffff;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_READ)
+		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
+			 __func__, reg, retval);
+	return retval;
+}
+
+static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
+				enum rtl8xxxu_rfpath path, u8 reg, u32 data)
+{
+	int ret, retval;
+	u32 dataaddr;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_WRITE)
+		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
+			 __func__, reg, data);
+
+	data &= FPGA0_LSSI_PARM_DATA_MASK;
+	dataaddr = (reg << FPGA0_LSSI_PARM_ADDR_SHIFT) | data;
+
+	/* Use XB for path B */
+	ret = rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].lssiparm, dataaddr);
+	if (ret != sizeof(dataaddr))
+		retval = -EIO;
+	else
+		retval = 0;
+
+	udelay(1);
+
+	return retval;
+}
+
+static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c)
+{
+	struct device *dev = &priv->udev->dev;
+	int mbox_nr, retry, retval = 0;
+	int mbox_reg, mbox_ext_reg;
+	u8 val8;
+
+	mbox_nr = priv->next_mbox;
+
+	mbox_reg = REG_HMBOX_0 + (mbox_nr * 4);
+	mbox_ext_reg = REG_HMBOX_EXT_0 + (mbox_nr * 2);
+
+	mutex_lock(&priv->h2c_mutex);
+	/*
+	 * MBOX ready?
+	 */
+	retry = 100;
+	do {
+		val8 = rtl8xxxu_read8(priv, REG_HMTFR);
+		if (!(val8 & BIT(mbox_nr)))
+			break;
+	} while (retry--);
+
+	if (!retry) {
+		dev_dbg(dev, "%s: Mailbox busy\n", __func__);
+		retval = -EBUSY;
+		goto error;
+	}
+
+	/*
+	 * Need to swap as it's being swapped again by rtl8xxxu_write16/32()
+	 */
+	if (h2c->cmd.cmd & H2C_EXT) {
+		rtl8xxxu_write16(priv, mbox_ext_reg,
+				 le16_to_cpu(h2c->raw.ext));
+		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
+			dev_info(dev, "H2C_EXT %04x\n",
+				 le16_to_cpu(h2c->raw.ext));
+	}
+	rtl8xxxu_write32(priv, mbox_reg, le32_to_cpu(h2c->raw.data));
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
+		dev_info(dev, "H2C %08x\n", le32_to_cpu(h2c->raw.data));
+
+	priv->next_mbox = (mbox_nr + 1) % H2C_MAX_MBOX;
+
+error:
+	mutex_unlock(&priv->h2c_mutex);
+	return retval;
+}
+
+static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u32 val32;
+
+	val8 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
+	val8 |= BIT(0) | BIT(3);
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, val8);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
+	val32 &= ~(BIT(4) | BIT(5));
+	val32 |= BIT(3);
+	if (priv->rf_paths == 2) {
+		val32 &= ~(BIT(20) | BIT(21));
+		val32 |= BIT(19);
+	}
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	val32 &= ~OFDM_RF_PATH_TX_MASK;
+	if (priv->tx_paths == 2)
+		val32 |= OFDM_RF_PATH_TX_A | OFDM_RF_PATH_TX_B;
+	else if (priv->rtlchip == 0x8192c || priv->rtlchip == 0x8191c)
+		val32 |= OFDM_RF_PATH_TX_B;
+	else
+		val32 |= OFDM_RF_PATH_TX_A;
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 &= ~FPGA_RF_MODE_JAPAN;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x63db25a0);
+	else
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x631b25a0);
+
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x32d95);
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x32d95);
+
+#if 0
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE3);
+	rtl8xxxu_write8(priv, REG_APSD_CTRL, 0x00);
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE2);
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE3);
+#endif
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
+}
+
+static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv)
+{
+	u8 sps0;
+	u32 val32;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	sps0 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
+
+	/* RF RX code for preamble power saving */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
+	val32 &= ~(BIT(3) | BIT(4) | BIT(5));
+	if (priv->rf_paths == 2)
+		val32 &= ~(BIT(19) | BIT(20) | BIT(21));
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
+
+	/* Disable TX for four paths */
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	val32 &= ~OFDM_RF_PATH_TX_MASK;
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+	/* Enable power saving */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 |= FPGA_RF_MODE_JAPAN;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	/* AFE control register to power down bits [30:22] */
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00db25a0);
+	else
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x001b25a0);
+
+	/* Power down RF module */
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0);
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0);
+
+	sps0 &= ~(BIT(0) | BIT(3));
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, sps0);
+}
+
+
+static void rtl8723a_stop_tx_beacon(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
+	val8 &= ~BIT(6);
+	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
+
+	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 1, 0x64);
+	val8 = rtl8xxxu_read8(priv, REG_TBTT_PROHIBIT + 2);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8);
+}
+
+
+/*
+ * The rtl8723a has 3 channel groups for it's efuse settings. It only
+ * supports the 2.4GHz band, so channels 1 - 14:
+ *  group 0: channels 1 - 3
+ *  group 1: channels 4 - 9
+ *  group 2: channels 10 - 14
+ *
+ * Note: We index from 0 in the code
+ */
+static int rtl8723a_channel_to_group(int channel)
+{
+	int group;
+
+	if (channel < 4)
+		group = 0;
+	else if (channel < 10)
+		group = 1;
+	else
+		group = 2;
+
+	return group;
+}
+
+static void rtl8723au_config_channel(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u32 val32, rsr;
+	u8 val8, opmode;
+	bool ht = true;
+	int sec_ch_above;
+	int i;
+
+	for (i = RF_A; i < priv->rf_paths; i++) {
+		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
+		val32 &= ~MODE_AG_CHANNEL_MASK;
+		val32 |= hw->conf.chandef.chan->hw_value;
+		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
+	}
+
+	opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE);
+	rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+
+	switch (hw->conf.chandef.width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		ht = false;
+	case NL80211_CHAN_WIDTH_20:
+		opmode |= BW_OPMODE_20MHZ;
+		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+		val32 &= ~FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
+		val32 &= ~FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
+		val32 |= FPGA0_ANALOG2_20MHZ;
+		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
+		break;
+	case NL80211_CHAN_WIDTH_40:
+		if (hw->conf.chandef.center_freq1 >
+		    hw->conf.chandef.chan->center_freq)
+			sec_ch_above = 1;
+		else
+			sec_ch_above = 0;
+
+		opmode &= ~BW_OPMODE_20MHZ;
+		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
+		rsr &= ~RSR_RSC_BANDWIDTH_40M;
+		if (sec_ch_above)
+			rsr |= RSR_RSC_UPPER_SUB_CHANNEL;
+		else
+			rsr |= RSR_RSC_LOWER_SUB_CHANNEL;
+		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+		val32 |= FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
+		val32 |= FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
+
+		/*
+		 * Set Control channel to upper or lower. These settings
+		 * are required only for 40MHz
+		 */
+		val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM);
+		val32 &= ~CCK0_SIDEBAND;
+		if (!sec_ch_above)
+			val32 |= CCK0_SIDEBAND;
+		rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
+		val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */
+		if (sec_ch_above)
+			val32 |= OFDM_LSTF_PRIME_CH_LOW;
+		else
+			val32 |= OFDM_LSTF_PRIME_CH_HIGH;
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
+		val32 &= ~FPGA0_ANALOG2_20MHZ;
+		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
+		val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL);
+		if (sec_ch_above)
+			val32 |= FPGA0_PS_UPPER_CHANNEL;
+		else
+			val32 |= FPGA0_PS_LOWER_CHANNEL;
+		rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
+		break;
+
+	default:
+		break;
+	}
+
+	if (ht)
+		val8 = 0x0e;
+	else
+		val8 = 0x0a;
+
+	rtl8xxxu_write8(priv, REG_SIFS_CCK + 1, val8);
+	rtl8xxxu_write8(priv, REG_SIFS_OFDM + 1, val8);
+
+	rtl8xxxu_write16(priv, REG_R2T_SIFS, 0x0808);
+	rtl8xxxu_write16(priv, REG_T2T_SIFS, 0x0a0a);
+
+	for (i = RF_A; i < priv->rf_paths; i++) {
+		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
+		if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40)
+			val32 &= ~MODE_AG_CHANNEL_20MHZ;
+		else
+			val32 |= MODE_AG_CHANNEL_20MHZ;
+		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
+	}
+}
+
+static void
+rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
+{
+	u8 cck[RTL8723A_MAX_RF_PATHS], ofdm[RTL8723A_MAX_RF_PATHS];
+	u8 ofdmbase[RTL8723A_MAX_RF_PATHS], mcsbase[RTL8723A_MAX_RF_PATHS];
+	u32 val32, ofdm_a, ofdm_b, mcs_a, mcs_b;
+	u8 val8;
+	int group, i;
+
+	group = rtl8723a_channel_to_group(channel);
+
+	cck[0] = priv->cck_tx_power_index_A[group];
+	ofdm[0] = priv->ht40_1s_tx_power_index_A[group];
+
+	if (priv->rf_paths > 1) {
+		cck[1] = priv->cck_tx_power_index_B[group];
+		ofdm[1] = priv->ht40_1s_tx_power_index_B[group];
+	} else {
+		cck[1] = 0;
+		ofdm[1] = 0;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
+		dev_info(&priv->udev->dev,
+			 "%s: Setting TX power CCK A: %02x, "
+			 "CCK B: %02x, OFDM A: %02x, OFDM B: %02x\n",
+			 __func__, cck[0], cck[1], ofdm[0], ofdm[1]);
+
+	for (i = 0; i < RTL8723A_MAX_RF_PATHS; i++) {
+		if (cck[i] > RF6052_MAX_TX_PWR)
+			cck[i] = RF6052_MAX_TX_PWR;
+		if (ofdm[i] > RF6052_MAX_TX_PWR)
+			ofdm[i] = RF6052_MAX_TX_PWR;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32);
+	val32 &= 0xffff00ff;
+	val32 |= (cck[0] << 8);
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+	val32 &= 0xff;
+	val32 |= ((cck[0] << 8) | (cck[0] << 16) | (cck[0] << 24));
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+	val32 &= 0xffffff00;
+	val32 |= cck[1];
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK1_55_MCS32);
+	val32 &= 0xff;
+	val32 |= ((cck[1] << 8) | (cck[1] << 16) | (cck[1] << 24));
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK1_55_MCS32, val32);
+
+	ofdmbase[0] = ofdm[0] +	priv->ofdm_tx_power_index_diff[group].a;
+	mcsbase[0] = ofdm[0];
+	if (!ht40)
+		mcsbase[0] += priv->ht20_tx_power_index_diff[group].a;
+
+	ofdmbase[1] = ofdm[1] +	priv->ofdm_tx_power_index_diff[group].b;
+	mcsbase[1] = ofdm[1];
+	if (!ht40)
+		mcsbase[1] += priv->ht20_tx_power_index_diff[group].b;
+
+	ofdm_a = ofdmbase[0] | ofdmbase[0] << 8 |
+		ofdmbase[0] << 16 | ofdmbase[0] << 24;
+	ofdm_b = ofdmbase[1] | ofdmbase[1] << 8 |
+		ofdmbase[1] << 16 | ofdmbase[1] << 24;
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm_b);
+
+	mcs_a = mcsbase[0] | mcsbase[0] << 8 |
+		mcsbase[0] << 16 | mcsbase[0] << 24;
+	mcs_b = mcsbase[1] | mcsbase[1] << 8 |
+		mcsbase[1] << 16 | mcsbase[1] << 24;
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs_a);
+	for (i = 0; i < 3; i++) {
+		if (i != 2)
+			val8 = (mcsbase[0] > 8) ? (mcsbase[0] - 8) : 0;
+		else
+			val8 = (mcsbase[0] > 6) ? (mcsbase[0] - 6) : 0;
+		rtl8xxxu_write8(priv, REG_OFDM0_XC_TX_IQ_IMBALANCE + i, val8);
+	}
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs_b);
+	for (i = 0; i < 3; i++) {
+		if (i != 2)
+			val8 = (mcsbase[1] > 8) ? (mcsbase[1] - 8) : 0;
+		else
+			val8 = (mcsbase[1] > 6) ? (mcsbase[1] - 6) : 0;
+		rtl8xxxu_write8(priv, REG_OFDM0_XD_TX_IQ_IMBALANCE + i, val8);
+	}
+}
+
+static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
+				  enum nl80211_iftype linktype)
+{
+	u16 val8;
+
+	val8 = rtl8xxxu_read16(priv, REG_MSR);
+	val8 &= ~MSR_LINKTYPE_MASK;
+
+	switch (linktype) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		val8 |= MSR_LINKTYPE_NONE;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		val8 |= MSR_LINKTYPE_ADHOC;
+		break;
+	case NL80211_IFTYPE_STATION:
+		val8 |= MSR_LINKTYPE_STATION;
+		break;
+	case NL80211_IFTYPE_AP:
+		val8 |= MSR_LINKTYPE_AP;
+		break;
+	default:
+		goto out;
+	}
+
+	rtl8xxxu_write8(priv, REG_MSR, val8);
+out:
+	return;
+}
+
+static void
+rtl8xxxu_set_retry(struct rtl8xxxu_priv *priv, u16 short_retry, u16 long_retry)
+{
+	u16 val16;
+
+	val16 = ((short_retry << RETRY_LIMIT_SHORT_SHIFT) &
+		 RETRY_LIMIT_SHORT_MASK) |
+		((long_retry << RETRY_LIMIT_LONG_SHIFT) &
+		 RETRY_LIMIT_LONG_MASK);
+
+	rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
+}
+
+static void
+rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm)
+{
+	u16 val16;
+
+	val16 = ((cck << SPEC_SIFS_CCK_SHIFT) & SPEC_SIFS_CCK_MASK) |
+		((ofdm << SPEC_SIFS_OFDM_SHIFT) & SPEC_SIFS_OFDM_MASK);
+
+	rtl8xxxu_write16(priv, REG_SPEC_SIFS, val16);
+}
+
+static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	char *cut;
+
+	switch (priv->chip_cut) {
+	case 0:
+		cut = "A";
+		break;
+	case 1:
+		cut = "B";
+		break;
+	default:
+		cut = "unknown";
+	}
+
+	dev_info(dev,
+		 "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n",
+		 priv->chip_name, cut, priv->vendor_umc ? "UMC" : "TSMC",
+		 priv->tx_paths, priv->rx_paths, priv->ep_tx_count,
+		 priv->has_wifi, priv->has_bluetooth, priv->has_gps,
+		 priv->hi_pa);
+
+	dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr);
+}
+
+static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	u32 val32, bonding;
+	u16 val16;
+
+	val32 = rtl8xxxu_read32(priv, REG_SYS_CFG);
+	priv->chip_cut = (val32 & SYS_CFG_CHIP_VERSION_MASK) >>
+		SYS_CFG_CHIP_VERSION_SHIFT;
+	if (val32 & SYS_CFG_TRP_VAUX_EN) {
+		dev_info(dev, "Unsupported test chip\n");
+		return -ENOTSUPP;
+	}
+
+	if (val32 & SYS_CFG_BT_FUNC) {
+		sprintf(priv->chip_name, "8723AU");
+		priv->rf_paths = 1;
+		priv->rx_paths = 1;
+		priv->tx_paths = 1;
+		priv->rtlchip = 0x8723a;
+
+		val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL);
+		if (val32 & MULTI_WIFI_FUNC_EN)
+			priv->has_wifi = 1;
+		if (val32 & MULTI_BT_FUNC_EN)
+			priv->has_bluetooth = 1;
+		if (val32 & MULTI_GPS_FUNC_EN)
+			priv->has_gps = 1;
+	} else if (val32 & SYS_CFG_TYPE_ID) {
+		bonding = rtl8xxxu_read32(priv, REG_HPON_FSM);
+		bonding &= HPON_FSM_BONDING_MASK;
+		if (bonding == HPON_FSM_BONDING_1T2R) {
+			sprintf(priv->chip_name, "8191CU");
+			priv->rf_paths = 2;
+			priv->rx_paths = 2;
+			priv->tx_paths = 1;
+			priv->rtlchip = 0x8191c;
+		} else {
+			sprintf(priv->chip_name, "8192CU");
+			priv->rf_paths = 2;
+			priv->rx_paths = 2;
+			priv->tx_paths = 2;
+			priv->rtlchip = 0x8192c;
+		}
+		priv->has_wifi = 1;
+	} else {
+		sprintf(priv->chip_name, "8188CU");
+		priv->rf_paths = 1;
+		priv->rx_paths = 1;
+		priv->tx_paths = 1;
+		priv->rtlchip = 0x8188c;
+		priv->has_wifi = 1;
+	}
+
+	if (val32 & SYS_CFG_VENDOR_ID)
+		priv->vendor_umc = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS);
+	priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28;
+
+	val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX);
+	if (val16 & NORMAL_SIE_EP_TX_HIGH_MASK) {
+		priv->ep_tx_high_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	if (val16 & NORMAL_SIE_EP_TX_NORMAL_MASK) {
+		priv->ep_tx_normal_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	if (val16 & NORMAL_SIE_EP_TX_LOW_MASK) {
+		priv->ep_tx_low_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	/*
+	 * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX
+	 */
+	if (!priv->ep_tx_count) {
+		switch (priv->nr_out_eps) {
+		case 3:
+			priv->ep_tx_low_queue = 1;
+			priv->ep_tx_count++;
+		case 2:
+			priv->ep_tx_normal_queue = 1;
+			priv->ep_tx_count++;
+		case 1:
+			priv->ep_tx_high_queue = 1;
+			priv->ep_tx_count++;
+			break;
+		default:
+			dev_info(dev, "Unsupported USB TX end-points\n");
+			return -ENOTSUPP;
+		}
+	}
+
+	return 0;
+}
+
+static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
+{
+	if (priv->efuse_wifi.efuse8723.rtl_id != cpu_to_le16(0x8129))
+		return -EINVAL;
+
+	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723.mac_addr);
+
+	memcpy(priv->cck_tx_power_index_A,
+	       priv->efuse_wifi.efuse8723.cck_tx_power_index_A,
+	       sizeof(priv->cck_tx_power_index_A));
+	memcpy(priv->cck_tx_power_index_B,
+	       priv->efuse_wifi.efuse8723.cck_tx_power_index_B,
+	       sizeof(priv->cck_tx_power_index_B));
+
+	memcpy(priv->ht40_1s_tx_power_index_A,
+	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_A,
+	       sizeof(priv->ht40_1s_tx_power_index_A));
+	memcpy(priv->ht40_1s_tx_power_index_B,
+	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_B,
+	       sizeof(priv->ht40_1s_tx_power_index_B));
+
+	memcpy(priv->ht20_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8723.ht20_tx_power_index_diff,
+	       sizeof(priv->ht20_tx_power_index_diff));
+	memcpy(priv->ofdm_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8723.ofdm_tx_power_index_diff,
+	       sizeof(priv->ofdm_tx_power_index_diff));
+
+	memcpy(priv->ht40_max_power_offset,
+	       priv->efuse_wifi.efuse8723.ht40_max_power_offset,
+	       sizeof(priv->ht40_max_power_offset));
+	memcpy(priv->ht20_max_power_offset,
+	       priv->efuse_wifi.efuse8723.ht20_max_power_offset,
+	       sizeof(priv->ht20_max_power_offset));
+
+	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
+		 priv->efuse_wifi.efuse8723.vendor_name);
+	dev_info(&priv->udev->dev, "Product: %.41s\n",
+		 priv->efuse_wifi.efuse8723.device_name);
+	return 0;
+}
+
+static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
+{
+	int i;
+
+	if (priv->efuse_wifi.efuse8192.rtl_id != cpu_to_le16(0x8129))
+		return -EINVAL;
+
+	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192.mac_addr);
+
+	memcpy(priv->cck_tx_power_index_A,
+	       priv->efuse_wifi.efuse8192.cck_tx_power_index_A,
+	       sizeof(priv->cck_tx_power_index_A));
+	memcpy(priv->cck_tx_power_index_B,
+	       priv->efuse_wifi.efuse8192.cck_tx_power_index_B,
+	       sizeof(priv->cck_tx_power_index_B));
+
+	memcpy(priv->ht40_1s_tx_power_index_A,
+	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_A,
+	       sizeof(priv->ht40_1s_tx_power_index_A));
+	memcpy(priv->ht40_1s_tx_power_index_B,
+	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_B,
+	       sizeof(priv->ht40_1s_tx_power_index_B));
+	memcpy(priv->ht40_2s_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ht40_2s_tx_power_index_diff,
+	       sizeof(priv->ht40_2s_tx_power_index_diff));
+
+	memcpy(priv->ht20_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ht20_tx_power_index_diff,
+	       sizeof(priv->ht20_tx_power_index_diff));
+	memcpy(priv->ofdm_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ofdm_tx_power_index_diff,
+	       sizeof(priv->ofdm_tx_power_index_diff));
+
+	memcpy(priv->ht40_max_power_offset,
+	       priv->efuse_wifi.efuse8192.ht40_max_power_offset,
+	       sizeof(priv->ht40_max_power_offset));
+	memcpy(priv->ht20_max_power_offset,
+	       priv->efuse_wifi.efuse8192.ht20_max_power_offset,
+	       sizeof(priv->ht20_max_power_offset));
+
+	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
+		 priv->efuse_wifi.efuse8192.vendor_name);
+	dev_info(&priv->udev->dev, "Product: %.20s\n",
+		 priv->efuse_wifi.efuse8192.device_name);
+
+	if (priv->efuse_wifi.efuse8192.rf_regulatory & 0x20) {
+		sprintf(priv->chip_name, "8188RU");
+		priv->hi_pa = 1;
+	}
+
+	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02lx bytes):\n",
+		 __func__, sizeof(struct rtl8192cu_efuse));
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
+		unsigned char *raw = priv->efuse_wifi.raw;
+
+		for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) {
+			dev_info(&priv->udev->dev, "%02x: "
+				 "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+				 raw[i], raw[i + 1], raw[i + 2],
+				 raw[i + 3], raw[i + 4], raw[i + 5],
+				 raw[i + 6], raw[i + 7]);
+		}
+	}
+	return 0;
+}
+
+static int
+rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data)
+{
+	int i;
+	u8 val8;
+	u32 val32;
+
+	/* Write Address */
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 1, offset & 0xff);
+	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 2);
+	val8 &= 0xfc;
+	val8 |= (offset >> 8) & 0x03;
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 2, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 3);
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 3, val8 & 0x7f);
+
+	/* Poll for data read */
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+	for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+		if (val32 & BIT(31))
+			break;
+	}
+
+	if (i == RTL8XXXU_MAX_REG_POLL)
+		return -EIO;
+
+	udelay(50);
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+
+	*data = val32 & 0xff;
+	return 0;
+}
+
+static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int i, ret = 0;
+	u8 val8, word_mask, header, extheader;
+	u16 val16, efuse_addr, offset;
+	u32 val32;
+
+	val16 = rtl8xxxu_read16(priv, REG_9346CR);
+	if (val16 & EEPROM_ENABLE)
+		priv->has_eeprom = 1;
+	if (val16 & EEPROM_BOOT)
+		priv->boot_eeprom = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST);
+	val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT;
+	rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32);
+
+	dev_dbg(dev, "Booting from %s\n",
+		priv->boot_eeprom ? "EEPROM" : "EFUSE");
+
+	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_ENABLE);
+
+	/*  1.2V Power: From VDDON with Power Cut(0x0000[15]), default valid */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
+	if (!(val16 & SYS_ISO_PWC_EV12V)) {
+		val16 |= SYS_ISO_PWC_EV12V;
+		rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
+	}
+	/*  Reset: 0x0000[28], default valid */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	if (!(val16 & SYS_FUNC_ELDR)) {
+		val16 |= SYS_FUNC_ELDR;
+		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+	}
+
+	/*
+	 * Clock: Gated(0x0008[5]) 8M(0x0008[1]) clock from ANA, default valid
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR);
+	if (!(val16 & SYS_CLK_LOADER_ENABLE) || !(val16 & SYS_CLK_ANA8M)) {
+		val16 |= (SYS_CLK_LOADER_ENABLE | SYS_CLK_ANA8M);
+		rtl8xxxu_write16(priv, REG_SYS_CLKR, val16);
+	}
+
+	/* Default value is 0xff */
+	memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN_8723A);
+
+	efuse_addr = 0;
+	while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) {
+		ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &header);
+		if (ret || header == 0xff)
+			goto exit;
+
+		if ((header & 0x1f) == 0x0f) {	/* extended header */
+			offset = (header & 0xe0) >> 5;
+
+			ret = rtl8xxxu_read_efuse8(priv, efuse_addr++,
+						   &extheader);
+			if (ret)
+				goto exit;
+			/* All words disabled */
+			if ((extheader & 0x0f) == 0x0f)
+				continue;
+
+			offset |= ((extheader & 0xf0) >> 1);
+			word_mask = extheader & 0x0f;
+		} else {
+			offset = (header >> 4) & 0x0f;
+			word_mask = header & 0x0f;
+		}
+
+		if (offset < EFUSE_MAX_SECTION_8723A) {
+			u16 map_addr;
+			/* Get word enable value from PG header */
+
+			/* We have 8 bits to indicate validity */
+			map_addr = offset * 8;
+			if (map_addr >= EFUSE_MAP_LEN_8723A) {
+				dev_warn(dev, "%s: Illegal map_addr (%04x), "
+					 "efuse corrupt!\n",
+					 __func__, map_addr);
+				ret = -EINVAL;
+				goto exit;
+			}
+			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+				/* Check word enable condition in the section */
+				if (!(word_mask & BIT(i))) {
+					ret = rtl8xxxu_read_efuse8(priv,
+								   efuse_addr++,
+								   &val8);
+					if (ret)
+						goto exit;
+					priv->efuse_wifi.raw[map_addr++] = val8;
+
+					ret = rtl8xxxu_read_efuse8(priv,
+								   efuse_addr++,
+								   &val8);
+					if (ret)
+						goto exit;
+					priv->efuse_wifi.raw[map_addr++] = val8;
+				} else
+					map_addr += 2;
+			}
+		} else {
+			dev_warn(dev,
+				 "%s: Illegal offset (%04x), efuse corrupt!\n",
+				 __func__, offset);
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+
+exit:
+	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_DISABLE);
+
+	return ret;
+}
+
+static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int ret = 0, i;
+	u32 val32;
+
+	/* Poll checksum report */
+	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+		if (val32 & MCU_FW_DL_CSUM_REPORT)
+			break;
+	}
+
+	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
+		dev_warn(dev, "Firmware checksum poll timed out\n");
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+	val32 |= MCU_FW_DL_READY;
+	val32 &= ~MCU_WINT_INIT_READY;
+	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32);
+
+	/* Wait for firmware to become ready */
+	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+		if (val32 & MCU_WINT_INIT_READY)
+			break;
+
+		udelay(100);
+	}
+
+	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
+		dev_warn(dev, "Firmware failed to start\n");
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
+{
+	int pages, remainder, i, ret;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	u8 *fwptr;
+
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1);
+	val8 |= 4;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, val8);
+
+	/* 8051 enable */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE);
+
+	/* MCU firmware download enable */
+	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE);
+
+	/* 8051 reset */
+	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19));
+
+	/* Reset firmware download checksum */
+	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT);
+
+	pages = priv->fw_size / RTL_FW_PAGE_SIZE;
+	remainder = priv->fw_size % RTL_FW_PAGE_SIZE;
+
+	fwptr = priv->fw_data->data;
+
+	for (i = 0; i < pages; i++) {
+		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
+		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+
+		ret = priv->fops->writeN(priv, REG_FW_START_ADDRESS,
+					 fwptr, RTL_FW_PAGE_SIZE);
+		if (ret != RTL_FW_PAGE_SIZE) {
+			ret = -EAGAIN;
+			goto fw_abort;
+		}
+
+		fwptr += RTL_FW_PAGE_SIZE;
+	}
+
+	if (remainder) {
+		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
+		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+		ret = priv->fops->writeN(priv, REG_FW_START_ADDRESS,
+					 fwptr, remainder);
+		if (ret != remainder) {
+			ret = -EAGAIN;
+			goto fw_abort;
+		}
+	}
+
+	ret = 0;
+fw_abort:
+	/* MCU firmware download disable */
+	val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write16(priv, REG_MCU_FW_DL,
+			 val16 & (~MCU_FW_DL_ENABLE & 0xff));
+
+	return ret;
+}
+
+static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name)
+{
+	struct device *dev = &priv->udev->dev;
+	const struct firmware *fw;
+	int ret = 0;
+	u16 signature;
+
+	dev_info(dev, "%s: Loading firmware %s\n", DRIVER_NAME, fw_name);
+	if (request_firmware(&fw, fw_name, &priv->udev->dev)) {
+		dev_warn(dev, "request_firmware(%s) failed\n", fw_name);
+		ret = -EAGAIN;
+		goto exit;
+	}
+	if (!fw) {
+		dev_warn(dev, "Firmware data not available\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+	priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header);
+
+	signature = le16_to_cpu(priv->fw_data->signature);
+	switch (signature & 0xfff0) {
+	case 0x92c0:
+	case 0x88c0:
+	case 0x2300:
+		break;
+	default:
+		ret = -EINVAL;
+		dev_warn(dev, "%s: Invalid firmware signature: 0x%04x\n",
+			 __func__, signature);
+	}
+
+	dev_info(dev, "Firmware revision %i.%i (signature 0x%04x)\n",
+		 le16_to_cpu(priv->fw_data->major_version),
+		 priv->fw_data->minor_version, signature);
+
+exit:
+	release_firmware(fw);
+	return ret;
+}
+
+static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv)
+{
+	char *fw_name;
+	int ret;
+
+	switch (priv->chip_cut) {
+	case 0:
+		fw_name = "rtlwifi/rtl8723aufw_A.bin";
+		break;
+	case 1:
+		if (priv->enable_bluetooth)
+			fw_name = "rtlwifi/rtl8723aufw_B.bin";
+		else
+			fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = rtl8xxxu_load_firmware(priv, fw_name);
+	return ret;
+}
+
+static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv)
+{
+	char *fw_name;
+	int ret;
+
+	if (!priv->vendor_umc)
+		fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
+	else if (priv->chip_cut || priv->rtlchip == 0x8192c)
+		fw_name = "rtlwifi/rtl8192cufw_B.bin";
+	else
+		fw_name = "rtlwifi/rtl8192cufw_A.bin";
+
+	ret = rtl8xxxu_load_firmware(priv, fw_name);
+
+	return ret;
+}
+
+static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv)
+{
+	u16 val16;
+	int i = 100;
+
+	/* Inform 8051 to perform reset */
+	rtl8xxxu_write8(priv, REG_HMTFR + 3, 0x20);
+
+	for (i = 100; i > 0; i--) {
+		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+
+		if (!(val16 & SYS_FUNC_CPU_ENABLE)) {
+			dev_dbg(&priv->udev->dev,
+				"%s: Firmware self reset success!\n", __func__);
+			break;
+		}
+		udelay(50);
+	}
+
+	if (!i) {
+		/* Force firmware reset */
+		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+		val16 &= ~SYS_FUNC_CPU_ENABLE;
+		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+	}
+}
+
+static int
+rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array)
+{
+	int i, ret;
+	u16 reg;
+	u8 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xffff && val == 0xff)
+			break;
+
+		ret = rtl8xxxu_write8(priv, reg, val);
+		if (ret != 1) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize MAC\n");
+			return -EAGAIN;
+		}
+	}
+
+	rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a);
+
+	return 0;
+}
+
+static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_reg32val *array)
+{
+	int i, ret;
+	u16 reg;
+	u32 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xffff && val == 0xffffffff)
+			break;
+
+		ret = rtl8xxxu_write32(priv, reg, val);
+		if (ret != sizeof(val)) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize PHY\n");
+			return -EAGAIN;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+/*
+ * Most of this is black magic retrieved from the old rtl8723au driver
+ */
+static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
+{
+	u8 val8, ldoa15, ldov12d, lpldo, ldohci12;
+	u32 val32;
+
+	/*
+	 * Todo: The vendor driver maintains a table of PHY register
+	 *       addresses, which is initialized here. Do we need this?
+	 */
+
+	val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
+	udelay(2);
+	val8 |= AFE_PLL_320_ENABLE;
+	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
+	udelay(2);
+
+	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff);
+	udelay(2);
+
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	/* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */
+	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
+	val32 &= ~AFE_XTAL_RF_GATE;
+	if (priv->has_bluetooth)
+		val32 &= ~AFE_XTAL_BT_GATE;
+	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
+
+	/* 6. 0x1f[7:0] = 0x07 */
+	val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
+	rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
+
+	if (priv->hi_pa)
+		rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table);
+	else if (priv->tx_paths == 2)
+		rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table);
+	else
+		rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table);
+
+
+	if (priv->rtlchip == 0x8188c && priv->hi_pa &&
+	    priv->vendor_umc && priv->chip_cut == 1)
+		rtl8xxxu_write8(priv, REG_OFDM0_AGC_PARM1 + 2, 0x50);
+
+	if (priv->tx_paths == 1 && priv->rx_paths == 2) {
+		/*
+		 * For 1T2R boards, patch the registers.
+		 *
+		 * It looks like 8191/2 1T2R boards use path B for TX
+		 */
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO);
+		val32 &= ~(BIT(0) | BIT(1));
+		val32 |= BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO);
+		val32 &= ~0x300033;
+		val32 |= 0x200022;
+		rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
+		val32 &= 0xff000000;
+		val32 |= 0x45000000;
+		rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+		val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK);
+		val32 |= (OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B |
+			  OFDM_RF_PATH_TX_B);
+		rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGC_PARM1);
+		val32 &= ~(BIT(4) | BIT(5));
+		val32 |= BIT(4);
+		rtl8xxxu_write32(priv, REG_OFDM0_AGC_PARM1, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_RFON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_CCK_RFON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_BBON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_CCK_BBON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_RFON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_OFDM_RFON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_BBON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_OFDM_BBON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_TO_TX);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_TO_TX, val32);
+	}
+
+	if (priv->hi_pa)
+		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table);
+	else
+		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table);
+
+	if (priv->rtlchip == 0x8723a &&
+	    priv->efuse_wifi.efuse8723.version >= 0x01) {
+		val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);
+
+		val8 = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
+		val32 &= 0xff000fff;
+		val32 |= ((val8 | (val8 << 6)) << 12);
+
+		rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);
+	}
+
+	ldoa15 = LDOA15_ENABLE | LDOA15_OBUF;
+	ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT);
+	ldohci12 = 0x57;
+	lpldo = 1;
+	val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15;
+
+	rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32);
+
+	return 0;
+}
+
+static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv,
+				 struct rtl8xxxu_rfregval *array,
+				 enum rtl8xxxu_rfpath path)
+{
+	int i, ret;
+	u8 reg;
+	u32 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xff && val == 0xffffffff)
+			break;
+
+		switch (reg) {
+		case 0xfe:
+			msleep(50);
+			continue;
+		case 0xfd:
+			mdelay(5);
+			continue;
+		case 0xfc:
+			mdelay(1);
+			continue;
+		case 0xfb:
+			udelay(50);
+			continue;
+		case 0xfa:
+			udelay(5);
+			continue;
+		case 0xf9:
+			udelay(1);
+			continue;
+		}
+
+		reg &= 0x3f;
+
+		ret = rtl8xxxu_write_rfreg(priv, path, reg, val);
+		if (ret) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize RF\n");
+			return -EAGAIN;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv,
+				struct rtl8xxxu_rfregval *table,
+				enum rtl8xxxu_rfpath path)
+{
+	u32 val32;
+	u16 val16, rfsi_rfenv;
+	u16 reg_sw_ctrl, reg_int_oe, reg_hssi_parm2;
+
+	switch (path) {
+	case RF_A:
+		reg_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL;
+		reg_int_oe = REG_FPGA0_XA_RF_INT_OE;
+		reg_hssi_parm2 = REG_FPGA0_XA_HSSI_PARM2;
+		break;
+	case RF_B:
+		reg_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL;
+		reg_int_oe = REG_FPGA0_XB_RF_INT_OE;
+		reg_hssi_parm2 = REG_FPGA0_XB_HSSI_PARM2;
+		break;
+	default:
+		dev_err(&priv->udev->dev, "%s:Unsupported RF path %c\n",
+			__func__, path + 'A');
+		return -EINVAL;
+	}
+	/* For path B, use XB */
+	rfsi_rfenv = rtl8xxxu_read16(priv, reg_sw_ctrl);
+	rfsi_rfenv &= FPGA0_RF_RFENV;
+
+	/*
+	 * These two we might be able to optimize into one
+	 */
+	val32 = rtl8xxxu_read32(priv, reg_int_oe);
+	val32 |= BIT(20);	/* 0x10 << 16 */
+	rtl8xxxu_write32(priv, reg_int_oe, val32);
+	udelay(1);
+
+	val32 = rtl8xxxu_read32(priv, reg_int_oe);
+	val32 |= BIT(4);
+	rtl8xxxu_write32(priv, reg_int_oe, val32);
+	udelay(1);
+
+	/*
+	 * These two we might be able to optimize into one
+	 */
+	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
+	val32 &= ~FPGA0_HSSI_3WIRE_ADDR_LEN;
+	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
+	udelay(1);
+
+	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
+	val32 &= ~FPGA0_HSSI_3WIRE_DATA_LEN;
+	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
+	udelay(1);
+
+	rtl8xxxu_init_rf_regs(priv, table, path);
+
+	/* For path B, use XB */
+	val16 = rtl8xxxu_read16(priv, reg_sw_ctrl);
+	val16 &= ~FPGA0_RF_RFENV;
+	val16 |= rfsi_rfenv;
+	rtl8xxxu_write16(priv, reg_sw_ctrl, val16);
+
+	return 0;
+}
+
+static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data)
+{
+	int ret = -EBUSY;
+	int count = 0;
+	u32 value;
+
+	value = LLT_OP_WRITE | address << 8 | data;
+
+	rtl8xxxu_write32(priv, REG_LLT_INIT, value);
+
+	do {
+		value = rtl8xxxu_read32(priv, REG_LLT_INIT);
+		if ((value & LLT_OP_MASK) == LLT_OP_INACTIVE) {
+			ret = 0;
+			break;
+		}
+	} while (count++ < 20);
+
+	return ret;
+}
+
+static int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < last_tx_page; i++) {
+		ret = rtl8xxxu_llt_write(priv, i, i + 1);
+		if (ret)
+			goto exit;
+	}
+
+	ret = rtl8xxxu_llt_write(priv, last_tx_page, 0xff);
+	if (ret)
+		goto exit;
+
+	/* Mark remaining pages as a ring buffer */
+	for (i = last_tx_page + 1; i < 0xff; i++) {
+		ret = rtl8xxxu_llt_write(priv, i, (i + 1));
+		if (ret)
+			goto exit;
+	}
+
+	/*  Let last entry point to the start entry of ring buffer */
+	ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1);
+	if (ret)
+		goto exit;
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv)
+{
+	u16 val16, hi, lo;
+	u16 hiq, mgq, bkq, beq, viq, voq;
+	int hip, mgp, bkp, bep, vip, vop;
+	int ret = 0;
+
+	switch (priv->ep_tx_count) {
+	case 1:
+		if (priv->ep_tx_high_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+		} else if (priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_normal_queue) {
+			hi = TRXDMA_QUEUE_NORMAL;
+		} else {
+			hi = 0;
+			ret = -EINVAL;
+		}
+
+		hiq = hi;
+		mgq = hi;
+		bkq = hi;
+		beq = hi;
+		viq = hi;
+		voq = hi;
+
+		hip = 0;
+		mgp = 0;
+		bkp = 0;
+		bep = 0;
+		vip = 0;
+		vop = 0;
+		break;
+	case 2:
+		if (priv->ep_tx_high_queue && priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+			lo = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_normal_queue && priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_NORMAL;
+			lo = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_high_queue && priv->ep_tx_normal_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+			lo = TRXDMA_QUEUE_NORMAL;
+		} else {
+			ret = -EINVAL;
+			hi = 0;
+			lo = 0;
+		}
+
+		hiq = hi;
+		mgq = hi;
+		bkq = lo;
+		beq = lo;
+		viq = hi;
+		voq = hi;
+
+		hip = 0;
+		mgp = 0;
+		bkp = 1;
+		bep = 1;
+		vip = 0;
+		vop = 0;
+		break;
+	case 3:
+		beq = TRXDMA_QUEUE_LOW;
+		bkq = TRXDMA_QUEUE_LOW;
+		viq = TRXDMA_QUEUE_NORMAL;
+		voq = TRXDMA_QUEUE_HIGH;
+		mgq = TRXDMA_QUEUE_HIGH;
+		hiq = TRXDMA_QUEUE_HIGH;
+
+		hip = hiq ^ 3;
+		mgp = mgq ^ 3;
+		bkp = bkq ^ 3;
+		bep = beq ^ 3;
+		vip = viq ^ 3;
+		vop = viq ^ 3;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	/*
+	 * None of the vendor drivers are configuring the beacon
+	 * queue here .... why?
+	 */
+	if (!ret) {
+		val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL);
+		val16 &= 0x7;
+		val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) |
+			(viq << TRXDMA_CTRL_VIQ_SHIFT) |
+			(beq << TRXDMA_CTRL_BEQ_SHIFT) |
+			(bkq << TRXDMA_CTRL_BKQ_SHIFT) |
+			(mgq << TRXDMA_CTRL_MGQ_SHIFT) |
+			(hiq << TRXDMA_CTRL_HIQ_SHIFT);
+		rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16);
+
+		priv->pipe_out[TXDESC_QUEUE_VO] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[vop]);
+		priv->pipe_out[TXDESC_QUEUE_VI] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[vip]);
+		priv->pipe_out[TXDESC_QUEUE_BE] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[bep]);
+		priv->pipe_out[TXDESC_QUEUE_BK] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[bkp]);
+		priv->pipe_out[TXDESC_QUEUE_BEACON] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
+		priv->pipe_out[TXDESC_QUEUE_MGNT] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[mgp]);
+		priv->pipe_out[TXDESC_QUEUE_HIGH] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[hip]);
+		priv->pipe_out[TXDESC_QUEUE_CMD] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
+	}
+
+	return ret;
+}
+
+static void rtl8xxxu_fill_iqk_matrix_a(struct rtl8xxxu_priv *priv,
+				       bool iqk_ok, int result[][8],
+				       int candidate, bool tx_only)
+{
+	u32 oldval, x, tx0_a, reg;
+	int y, tx0_c;
+	u32 val32;
+
+	if (!iqk_ok)
+		return;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	oldval = val32 >> 22;
+
+	x = result[candidate][0];
+	if ((x & 0x00000200) != 0)
+		x = x | 0xfffffc00;
+	tx0_a = (x * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= tx0_a;
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(31);
+	if ((x * oldval >> 7) & 0x1)
+		val32 |= BIT(31);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	y = result[candidate][1];
+	if ((y & 0x00000200) != 0)
+		y = y | 0xfffffc00;
+	tx0_c = (y * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XC_TX_AFE);
+	val32 &= ~0xf0000000;
+	val32 |= (((tx0_c & 0x3c0) >> 6) << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_XC_TX_AFE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	val32 &= ~0x003f0000;
+	val32 |= ((tx0_c & 0x3f) << 16);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(29);
+	if ((y * oldval >> 7) & 0x1)
+		val32 |= BIT(29);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	if (tx_only) {
+		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
+		return;
+	}
+
+	reg = result[candidate][2];
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= (reg & 0x3ff);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
+
+	reg = result[candidate][3] & 0x3F;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
+	val32 &= ~0xfc00;
+	val32 |= ((reg << 10) & 0xfc00);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
+
+	reg = (result[candidate][3] >> 6) & 0xF;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_RX_IQ_EXT_ANTA);
+	val32 &= ~0xf0000000;
+	val32 |= (reg << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_RX_IQ_EXT_ANTA, val32);
+}
+
+static void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv,
+				       bool iqk_ok, int result[][8],
+				       int candidate, bool tx_only)
+{
+	u32 oldval, x, tx1_a, reg;
+	int y, tx1_c;
+	u32 val32;
+
+	if (!iqk_ok)
+		return;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	oldval = val32 >> 22;
+
+	x = result[candidate][4];
+	if ((x & 0x00000200) != 0)
+		x = x | 0xfffffc00;
+	tx1_a = (x * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= tx1_a;
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(27);
+	if ((x * oldval >> 7) & 0x1)
+		val32 |= BIT(27);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	y = result[candidate][5];
+	if ((y & 0x00000200) != 0)
+		y = y | 0xfffffc00;
+	tx1_c = (y * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XD_TX_AFE);
+	val32 &= ~0xf0000000;
+	val32 |= (((tx1_c & 0x3c0) >> 6) << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_XD_TX_AFE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	val32 &= ~0x003f0000;
+	val32 |= ((tx1_c & 0x3f) << 16);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(25);
+	if ((y * oldval >> 7) & 0x1)
+		val32 |= BIT(25);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	if (tx_only) {
+		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
+		return;
+	}
+
+	reg = result[candidate][6];
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= (reg & 0x3ff);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
+
+	reg = result[candidate][7] & 0x3f;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
+	val32 &= ~0xfc00;
+	val32 |= ((reg << 10) & 0xfc00);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
+
+	reg = (result[candidate][7] >> 6) & 0xf;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE);
+	val32 &= ~0x0000f000;
+	val32 |= (reg << 12);
+	rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32);
+}
+
+#define MAX_TOLERANCE		5
+
+static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv,
+					int result[][8], int c1, int c2)
+{
+	u32 i, j, diff, simubitmap, bound = 0;
+	int candidate[2] = {-1, -1};	/* for path A and path B */
+	bool retval = true;
+
+	if (priv->tx_paths > 1)
+		bound = 8;
+	else
+		bound = 4;
+
+	simubitmap = 0;
+
+	for (i = 0; i < bound; i++) {
+		diff = (result[c1][i] > result[c2][i]) ?
+			(result[c1][i] - result[c2][i]) :
+			(result[c2][i] - result[c1][i]);
+		if (diff > MAX_TOLERANCE) {
+			if ((i == 2 || i == 6) && !simubitmap) {
+				if (result[c1][i] + result[c1][i + 1] == 0)
+					candidate[(i / 4)] = c2;
+				else if (result[c2][i] + result[c2][i + 1] == 0)
+					candidate[(i / 4)] = c1;
+				else
+					simubitmap = simubitmap | (1 << i);
+			} else {
+				simubitmap = simubitmap | (1 << i);
+			}
+		}
+	}
+
+	if (simubitmap == 0) {
+		for (i = 0; i < (bound / 4); i++) {
+			if (candidate[i] >= 0) {
+				for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+					result[3][j] = result[candidate[i]][j];
+				retval = false;
+			}
+		}
+		return retval;
+	} else if (!(simubitmap & 0x0f)) {
+		/* path A OK */
+		for (i = 0; i < 4; i++)
+			result[3][i] = result[c1][i];
+	} else if (!(simubitmap & 0xf0) && priv->tx_paths > 1) {
+		/* path B OK */
+		for (i = 4; i < 8; i++)
+			result[3][i] = result[c1][i];
+	}
+
+	return false;
+}
+
+static void
+rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv, const u32 *reg, u32 *backup)
+{
+	int i;
+
+	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		backup[i] = rtl8xxxu_read8(priv, reg[i]);
+
+	backup[i] = rtl8xxxu_read32(priv, reg[i]);
+}
+
+static void rtl8xxxu_restore_mac_regs(struct rtl8xxxu_priv *priv,
+				      const u32 *reg, u32 *backup)
+{
+	int i;
+
+	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		rtl8xxxu_write8(priv, reg[i], backup[i]);
+
+	rtl8xxxu_write32(priv, reg[i], backup[i]);
+}
+
+static void rtl8xxxu_save_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
+			       u32 *backup, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		backup[i] = rtl8xxxu_read32(priv, regs[i]);
+}
+
+static void rtl8xxxu_restore_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
+				  u32 *backup, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		rtl8xxxu_write32(priv, regs[i], backup[i]);
+}
+
+
+static void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs,
+				  bool path_a_on)
+{
+	u32 path_on;
+	int i;
+
+	path_on = path_a_on ? 0x04db25a4 : 0x0b1b25a4;
+	if (priv->tx_paths == 1) {
+		path_on = 0x0bdb25a0;
+		rtl8xxxu_write32(priv, regs[0], 0x0b1b25a0);
+	} else {
+		rtl8xxxu_write32(priv, regs[0], path_on);
+	}
+
+	for (i = 1 ; i < RTL8XXXU_ADDA_REGS ; i++)
+		rtl8xxxu_write32(priv, regs[i], path_on);
+}
+
+static void rtl8xxxu_mac_calibration(struct rtl8xxxu_priv *priv,
+				     const u32 *regs, u32 *backup)
+{
+	int i = 0;
+
+	rtl8xxxu_write8(priv, regs[i], 0x3f);
+
+	for (i = 1 ; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(3)));
+
+	rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(5)));
+}
+
+static int rtl8xxxu_iqk_path_a(struct rtl8xxxu_priv *priv)
+{
+	u32 reg_eac, reg_e94, reg_e9c, reg_ea4, val32;
+	int result = 0;
+
+	/* path-A IQK setting */
+	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1f);
+	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1f);
+	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82140102);
+
+	val32 = (priv->rf_paths > 1) ? 0x28160202 :
+		/*IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202: */
+		0x28160502;
+	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, val32);
+
+	/* path-B IQK setting */
+	if (priv->rf_paths > 1) {
+		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x10008c22);
+		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x10008c22);
+		rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82140102);
+		rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28160202);
+	}
+
+	/* LO calibration setting */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x001028d1);
+
+	/* One shot, path A LOK & IQK */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
+	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+	mdelay(1);
+
+	/* Check failed */
+	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+	reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
+	reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
+	reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2);
+
+	if (!(reg_eac & BIT(28)) &&
+	    ((reg_e94 & 0x03ff0000) != 0x01420000) &&
+	    ((reg_e9c & 0x03ff0000) != 0x00420000))
+		result |= 0x01;
+	else	/* If TX not OK, ignore RX */
+		goto out;
+
+	/* If TX is OK, check whether RX is OK */
+	if (!(reg_eac & BIT(27)) &&
+	    ((reg_ea4 & 0x03ff0000) != 0x01320000) &&
+	    ((reg_eac & 0x03ff0000) != 0x00360000))
+		result |= 0x02;
+	else
+		dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n",
+			 __func__);
+out:
+	return result;
+}
+
+static int rtl8xxxu_iqk_path_b(struct rtl8xxxu_priv *priv)
+{
+	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	int result = 0;
+
+	/* One shot, path B LOK & IQK */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002);
+	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000);
+
+	mdelay(1);
+
+	/* Check failed */
+	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+	reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+	reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+	reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+	reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+
+	if (!(reg_eac & BIT(31)) &&
+	    ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
+	    ((reg_ebc & 0x03ff0000) != 0x00420000))
+		result |= 0x01;
+	else
+		goto out;
+
+	if (!(reg_eac & BIT(30)) &&
+	    (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) &&
+	    (((reg_ecc & 0x03ff0000) >> 16) != 0x36))
+		result |= 0x02;
+	else
+		dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n",
+			 __func__);
+out:
+	return result;
+}
+
+static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
+				     int result[][8], int t)
+{
+	struct device *dev = &priv->udev->dev;
+	u32 i, val32;
+	int path_a_ok, path_b_ok;
+	int retry = 2;
+	const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
+		REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
+		REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
+		REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
+		REG_TX_OFDM_BBON, REG_TX_TO_RX,
+		REG_TX_TO_TX, REG_RX_CCK,
+		REG_RX_OFDM, REG_RX_WAIT_RIFS,
+		REG_RX_TO_RX, REG_STANDBY,
+		REG_SLEEP, REG_PMPD_ANAEN
+	};
+	const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
+		REG_TXPAUSE, REG_BEACON_CTRL,
+		REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
+	};
+	const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
+		REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
+		REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
+		REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
+		REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE
+	};
+
+	/*
+	 * Note: IQ calibration must be performed after loading
+	 *       PHY_REG.txt , and radio_a, radio_b.txt
+	 */
+
+	if (t == 0) {
+		/* Save ADDA parameters, turn Path A ADDA on */
+		rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
+				   RTL8XXXU_ADDA_REGS);
+		rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+		rtl8xxxu_save_regs(priv, iqk_bb_regs,
+				   priv->bb_backup, RTL8XXXU_BB_REGS);
+	}
+
+	rtl8xxxu_path_adda_on(priv, adda_regs, true);
+
+	if (t == 0) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
+		if (val32 & FPGA0_HSSI_PARM1_PI)
+			priv->pi_enabled = 1;
+	}
+
+	if (!priv->pi_enabled) {
+		/* Switch BB to PI mode to do IQ Calibration. */
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
+		rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 &= ~FPGA_RF_MODE_CCK;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
+	rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
+	rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
+	val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+	val32 &= ~BIT(10);
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
+	val32 &= ~BIT(10);
+	rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
+
+	if (priv->tx_paths > 1) {
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+		rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000);
+	}
+
+	/* MAC settings */
+	rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
+
+	/* Page B init */
+	rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000);
+
+	if (priv->tx_paths > 1)
+		rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000);
+
+	/* IQ calibration setting */
+	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+	rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+	rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
+	for (i = 0; i < retry; i++) {
+		path_a_ok = rtl8xxxu_iqk_path_a(priv);
+		if (path_a_ok == 0x03) {
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_BEFORE_IQK_A);
+			result[t][0] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_AFTER_IQK_A);
+			result[t][1] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_RX_POWER_BEFORE_IQK_A_2);
+			result[t][2] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_RX_POWER_AFTER_IQK_A_2);
+			result[t][3] = (val32 >> 16) & 0x3ff;
+			break;
+		} else if (i == (retry - 1) && path_a_ok == 0x01) {
+			/* TX IQK OK */
+			dev_dbg(dev, "%s: Path A IQK Only Tx Success!!\n",
+				__func__);
+
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_BEFORE_IQK_A);
+			result[t][0] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_AFTER_IQK_A);
+			result[t][1] = (val32 >> 16) & 0x3ff;
+		}
+	}
+
+	if (!path_a_ok)
+		dev_dbg(dev, "%s: Path A IQK failed!\n", __func__);
+
+	if (priv->tx_paths > 1) {
+		/*
+		 * Path A into standby
+		 */
+		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x0);
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+		/* Turn Path B ADDA on */
+		rtl8xxxu_path_adda_on(priv, adda_regs, false);
+
+		for (i = 0; i < retry; i++) {
+			path_b_ok = rtl8xxxu_iqk_path_b(priv);
+			if (path_b_ok == 0x03) {
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+				result[t][4] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+				result[t][5] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+				result[t][6] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+				result[t][7] = (val32 >> 16) & 0x3ff;
+				break;
+			} else if (i == (retry - 1) && path_b_ok == 0x01) {
+				/* TX IQK OK */
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+				result[t][4] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+				result[t][5] = (val32 >> 16) & 0x3ff;
+			}
+		}
+
+		if (!path_b_ok)
+			dev_dbg(dev, "%s: Path B IQK failed!\n", __func__);
+	}
+
+	/* Back to BB mode, load original value */
+	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0);
+
+	if (t) {
+		if (!priv->pi_enabled) {
+			/*
+			 * Switch back BB to SI mode after finishing
+			 * IQ Calibration
+			 */
+			val32 = 0x01000000;
+			rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, val32);
+			rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, val32);
+		}
+
+		/* Reload ADDA power saving parameters */
+		rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup,
+				      RTL8XXXU_ADDA_REGS);
+
+		/* Reload MAC parameters */
+		rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+
+		/* Reload BB parameters */
+		rtl8xxxu_restore_regs(priv, iqk_bb_regs,
+				      priv->bb_backup, RTL8XXXU_BB_REGS);
+
+		/* Restore RX initial gain */
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3);
+
+		if (priv->tx_paths > 1) {
+			rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM,
+					 0x00032ed3);
+		}
+
+		/* Load 0xe30 IQC default value */
+		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00);
+		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00);
+	}
+}
+
+static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int result[4][8];	/* last is final result */
+	int i, candidate;
+	bool path_a_ok, path_b_ok;
+	u32 reg_e94, reg_e9c, reg_ea4, reg_eac;
+	u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	s32 reg_tmp = 0;
+	bool simu;
+
+	memset(result, 0, sizeof(result));
+	candidate = -1;
+
+	path_a_ok = false;
+	path_b_ok = false;
+
+	rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+
+	for (i = 0; i < 3; i++) {
+		rtl8xxxu_phy_iqcalibrate(priv, result, i);
+
+		if (i == 1) {
+			simu = rtl8xxxu_simularity_compare(priv, result, 0, 1);
+			if (simu) {
+				candidate = 0;
+				break;
+			}
+		}
+
+		if (i == 2) {
+			simu = rtl8xxxu_simularity_compare(priv, result, 0, 2);
+			if (simu) {
+				candidate = 0;
+				break;
+			}
+
+			simu = rtl8xxxu_simularity_compare(priv, result, 1, 2);
+			if (simu) {
+				candidate = 1;
+			} else {
+				for (i = 0; i < 8; i++)
+					reg_tmp += result[3][i];
+
+				if (reg_tmp)
+					candidate = 3;
+				else
+					candidate = -1;
+			}
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		reg_e94 = result[i][0];
+		reg_e9c = result[i][1];
+		reg_ea4 = result[i][2];
+		reg_eac = result[i][3];
+		reg_eb4 = result[i][4];
+		reg_ebc = result[i][5];
+		reg_ec4 = result[i][6];
+		reg_ecc = result[i][7];
+	}
+
+	if (candidate >= 0) {
+		reg_e94 = result[candidate][0];
+		priv->rege94 =  reg_e94;
+		reg_e9c = result[candidate][1];
+		priv->rege9c = reg_e9c;
+		reg_ea4 = result[candidate][2];
+		reg_eac = result[candidate][3];
+		reg_eb4 = result[candidate][4];
+		priv->regeb4 = reg_eb4;
+		reg_ebc = result[candidate][5];
+		priv->regebc = reg_ebc;
+		reg_ec4 = result[candidate][6];
+		reg_ecc = result[candidate][7];
+		dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate);
+		dev_dbg(dev,
+			"%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x "
+			"ecc=%x\n ", __func__, reg_e94, reg_e9c,
+			reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc);
+		path_a_ok = true;
+		path_b_ok = true;
+	} else {
+		reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100;
+		reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0;
+	}
+
+	if (reg_e94 && candidate >= 0)
+		rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result,
+					   candidate, (reg_ea4 == 0));
+
+	if (priv->tx_paths > 1 && reg_eb4)
+		rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
+					   candidate, (reg_ec4 == 0));
+
+	rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+			   priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
+}
+
+static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
+{
+	u32 val32;
+	u32 rf_amode, rf_bmode = 0, lstf;
+
+	/* Check continuous TX and Packet TX */
+	lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
+
+	if (lstf & OFDM_LSTF_MASK) {
+		/* Disable all continuous TX */
+		val32 = lstf & ~OFDM_LSTF_MASK;
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
+
+		/* Read original RF mode Path A */
+		rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC);
+
+		/* Set RF mode to standby Path A */
+		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC,
+				     (rf_amode & 0x8ffff) | 0x10000);
+
+		/* Path-B */
+		if (priv->tx_paths > 1) {
+			rf_bmode = rtl8xxxu_read_rfreg(priv, RF_B,
+						       RF6052_REG_AC);
+
+			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
+					     (rf_bmode & 0x8ffff) | 0x10000);
+		}
+	} else {
+		/*  Deal with Packet TX case */
+		/*  block all queues */
+		rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+	}
+
+	/* Start LC calibration */
+	val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG);
+	val32 |= 0x08000;
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32);
+
+	msleep(100);
+
+	/* Restore original parameters */
+	if (lstf & OFDM_LSTF_MASK) {
+		/* Path-A */
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, lstf);
+		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, rf_amode);
+
+		/* Path-B */
+		if (priv->tx_paths > 1)
+			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
+					     rf_bmode);
+	} else /*  Deal with Packet TX case */
+		rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
+}
+
+static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv)
+{
+	int i;
+	u16 reg;
+
+	reg = REG_MACID;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]);
+
+	return 0;
+}
+
+static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid)
+{
+	int i;
+	u16 reg;
+
+	dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid);
+
+	reg = REG_BSSID;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl8xxxu_write8(priv, reg + i, bssid[i]);
+
+	return 0;
+}
+
+static void
+rtl8xxxu_set_ampdu_factor(struct rtl8xxxu_priv *priv, u8 ampdu_factor)
+{
+	u8 vals[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+	u8 max_agg = 0xf;
+	int i;
+
+	ampdu_factor = 1 << (ampdu_factor + 2);
+	if (ampdu_factor > max_agg)
+		ampdu_factor = max_agg;
+
+	for (i = 0; i < 4; i++) {
+		if ((vals[i] & 0xf0) > (ampdu_factor << 4))
+			vals[i] = (vals[i] & 0x0f) | (ampdu_factor << 4);
+
+		if ((vals[i] & 0x0f) > ampdu_factor)
+			vals[i] = (vals[i] & 0xf0) | ampdu_factor;
+
+		rtl8xxxu_write8(priv, REG_AGGLEN_LMT + i, vals[i]);
+	}
+}
+
+static void rtl8xxxu_set_ampdu_min_space(struct rtl8xxxu_priv *priv, u8 density)
+{
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_AMPDU_MIN_SPACE);
+	val8 &= 0xf8;
+	val8 |= density;
+	rtl8xxxu_write8(priv, REG_AMPDU_MIN_SPACE, val8);
+}
+
+static int rtl8xxxu_active_to_emu(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	int count, ret;
+
+	/* Start of rtl8723AU_card_enable_flow */
+	/* Act to Cardemu sequence*/
+	/* Turn off RF */
+	rtl8xxxu_write8(priv, REG_RF_CTRL, 0);
+
+	/* 0x004E[7] = 0, switch DPDT_SEL_P output from register 0x0065[2] */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 &= ~LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+	/* 0x0005[1] = 1 turn off MAC by HW state machine*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 |= BIT(1);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+		if ((val8 & BIT(1)) == 0)
+			break;
+		udelay(10);
+	}
+
+	if (!count) {
+		dev_warn(&priv->udev->dev, "%s: Disabling MAC timed out\n",
+			 __func__);
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* 0x0000[5] = 1 analog Ips to digital, 1:isolation */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+	val8 |= SYS_ISO_ANALOG_IPS;
+	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+
+	/* 0x0020[0] = 0 disable LDOA12 MACRO block*/
+	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
+	val8 &= ~LDOA15_ENABLE;
+	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u8 val32;
+	int count, ret;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	/*
+	 * Poll - wait for RX packet to complete
+	 */
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, 0x5f8);
+		if (!val32)
+			break;
+		udelay(10);
+	}
+
+	if (!count) {
+		dev_warn(&priv->udev->dev,
+			 "%s: RX poll timed out (0x05f8)\n", __func__);
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* Disable CCK and OFDM, clock gated */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 &= ~SYS_FUNC_BBRSTB;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	udelay(2);
+
+	/* Reset baseband */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 &= ~SYS_FUNC_BB_GLB_RSTN;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	/* Reset MAC TRX */
+	val8 = rtl8xxxu_read8(priv, REG_CR);
+	val8 = CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE;
+	rtl8xxxu_write8(priv, REG_CR, val8);
+
+	/* Reset MAC TRX */
+	val8 = rtl8xxxu_read8(priv, REG_CR + 1);
+	val8 &= ~BIT(1); /* CR_SECURITY_ENABLE */
+	rtl8xxxu_write8(priv, REG_CR + 1, val8);
+
+	/* Respond TX OK to scheduler */
+	val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST);
+	val8 |= DUAL_TSF_TX_OK;
+	rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8);
+
+exit:
+	return ret;
+}
+
+static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	/* Clear suspend enable and power down enable*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(7));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* 0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/
+	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
+
+	/* 0x04[12:11] = 11 enable WL suspend*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(4));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+}
+
+static int rtl8xxxu_emu_to_active(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u32 val32;
+	int count, ret = 0;
+
+	/* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/
+	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
+	val8 |= LDOA15_ENABLE;
+	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
+
+	/* 0x67[0] = 0 to disable BT_GPS_SEL pins*/
+	val8 = rtl8xxxu_read8(priv, 0x0067);
+	val8 &= ~BIT(4);
+	rtl8xxxu_write8(priv, 0x0067, val8);
+
+	mdelay(1);
+
+	/* 0x00[5] = 0 release analog Ips to digital, 1:isolation */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+	val8 &= ~SYS_ISO_ANALOG_IPS;
+	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+
+	/* disable SW LPS 0x04[10]= 0 */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(2);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* wait till 0x04[17] = 1 power ready*/
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+		if (val32 & BIT(17))
+			break;
+
+		udelay(10);
+	}
+
+	if (!count) {
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* We should be able to optimize the following three entries into one */
+
+	/* release WLON reset 0x04[16]= 1*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
+
+	/* disable HWPDN 0x04[15]= 0*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(7);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* disable WL suspend*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(4));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* set, then poll until 0 */
+	val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+	val32 |= APS_FSMCO_MAC_ENABLE;
+	rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
+
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+		if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
+			ret = 0;
+			break;
+		}
+		udelay(10);
+	}
+
+	if (!count) {
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */
+	/*
+	 * Note: Vendor driver actually clears this bit, despite the
+	 * documentation claims it's being set!
+	 */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 |= LEDCFG2_DPDT_SELECT;
+	val8 &= ~LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	/* 0x0007[7:0] = 0x20 SOP option to disable BG/MB */
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x20);
+
+	/* 0x04[12:11] = 01 enable WL suspend */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(4);
+	val8 |= BIT(3);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 |= BIT(7);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* 0x48[16] = 1 to enable GPIO9 as EXT wakeup */
+	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
+
+	return 0;
+}
+
+static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int ret;
+
+	/*
+	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
+	 */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
+
+	rtl8xxxu_disabled_to_emu(priv);
+
+	ret = rtl8xxxu_emu_to_active(priv);
+	if (ret)
+		goto exit;
+
+	/*
+	 * 0x0004[19] = 1, reset 8051
+	 */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
+	val8 |= BIT(3);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
+
+	/*
+	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
+	 * Set CR bit10 to enable 32k calibration.
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
+		  CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
+		  CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
+		  CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE |
+		  CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	/* For EFuse PG */
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+	val32 &= ~(BIT(28) | BIT(29) | BIT(30));
+	val32 |= (0x06 << 28);
+	rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32);
+exit:
+	return ret;
+}
+
+static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int i;
+
+	for (i = 100; i; i--) {
+		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO);
+		if (val8 & APS_FSMCO_PFM_ALDN)
+			break;
+	}
+
+	if (!i) {
+		pr_info("%s: Poll failed\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
+	 */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, 0x2b);
+	udelay(100);
+
+	val8 = rtl8xxxu_read8(priv, REG_LDOV12D_CTRL);
+	if (!(val8 & LDOV12D_ENABLE)) {
+		pr_info("%s: Enabling LDOV12D (%02x)\n", __func__, val8);
+		val8 |= LDOV12D_ENABLE;
+		rtl8xxxu_write8(priv, REG_LDOV12D_CTRL, val8);
+
+		udelay(100);
+
+		val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+		val8 &= ~SYS_ISO_MD2PP;
+		rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+	}
+
+	/*
+	 * Auto enable WLAN
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
+	val16 |= APS_FSMCO_MAC_ENABLE;
+	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
+
+	for (i = 1000; i; i--) {
+		val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
+		if (!(val16 & APS_FSMCO_MAC_ENABLE))
+			break;
+	}
+	if (!i) {
+		pr_info("%s: FSMCO_MAC_ENABLE poll failed\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Enable radio, GPIO, LED
+	 */
+	val16 = APS_FSMCO_HW_SUSPEND | APS_FSMCO_ENABLE_POWERDOWN |
+		APS_FSMCO_PFM_ALDN;
+	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
+
+	/*
+	 * Release RF digital isolation
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
+	val16 &= ~SYS_ISO_DIOR;
+	rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
+
+	val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
+	val8 &= ~APSD_CTRL_OFF;
+	rtl8xxxu_write8(priv, REG_APSD_CTRL, val8);
+	for (i = 200; i; i--) {
+		val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
+		if (!(val8 & APSD_CTRL_OFF_STATUS))
+			break;
+	}
+
+	if (!i) {
+		pr_info("%s: APSD_CTRL poll failed\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
+		CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | CR_PROTOCOL_ENABLE |
+		CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE;
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	/*
+	 * Workaround for 8188RU LNA power leakage problem.
+	 */
+	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
+		val32 &= ~BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
+	}
+	return 0;
+}
+
+static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+	/*
+	 * Workaround for 8188RU LNA power leakage problem.
+	 */
+	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
+		val32 |= BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
+	}
+
+	rtl8xxxu_active_to_lps(priv);
+
+	/* Turn off RF */
+	rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00);
+
+	/* Reset Firmware if running in RAM */
+	if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL)
+		rtl8xxxu_firmware_self_reset(priv);
+
+	/* Reset MCU */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	val16 &= ~SYS_FUNC_CPU_ENABLE;
+	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+
+	/* Reset MCU ready status */
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
+
+	rtl8xxxu_active_to_emu(priv);
+	rtl8xxxu_emu_to_disabled(priv);
+
+	/* Reset MCU IO Wrapper */
+	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+
+	/* RSV_CTRL 0x1C[7:0] = 0x0e  lock ISO/CLK/Power control register */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e);
+}
+
+static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	struct rtl8xxxu_rfregval *rftable;
+	bool macpower;
+	int ret;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+	/* Check if MAC is already powered on */
+	val8 = rtl8xxxu_read8(priv, REG_CR);
+
+	/*
+	 * Fix 92DU-VC S3 hang with the reason is that secondary mac is not
+	 * initialized. First MAC returns 0xea, second MAC returns 0x00
+	 */
+	if (val8 == 0xea)
+		macpower = false;
+	else
+		macpower = true;
+
+	ret = priv->fops->power_on(priv);
+	if (ret < 0) {
+		dev_warn(dev, "%s: Failed power on\n", __func__);
+		goto exit;
+	}
+
+	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+	if (!macpower) {
+		ret = rtl8xxxu_init_llt_table(priv, TX_TOTAL_PAGE_NUM);
+		if (ret) {
+			dev_warn(dev, "%s: LLT table init failed\n", __func__);
+			goto exit;
+		}
+	}
+
+	ret = rtl8xxxu_download_firmware(priv);
+	dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+	ret = rtl8xxxu_start_firmware(priv);
+	dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table);
+	dev_dbg(dev, "%s: init_mac %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_init_phy_bb(priv);
+	dev_dbg(dev, "%s: init_phy_bb %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	switch(priv->rtlchip) {
+	case 0x8723a:
+		rftable = rtl8723au_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8188c:
+		if (priv->hi_pa)
+			rftable = rtl8188ru_radioa_1t_highpa_table;
+		else
+			rftable = rtl8192cu_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8191c:
+		rftable = rtl8192cu_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8192c:
+		rftable = rtl8192cu_radioa_2t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		if (ret)
+			break;
+		rftable = rtl8192cu_radiob_2t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		goto exit;
+
+	/* Reduce 80M spur */
+	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+
+	/* RFSW Control - clear bit 14 ?? */
+	rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003);
+	/* 0x07000760 */
+	val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW |
+		FPGA0_RF_ANTSWB | FPGA0_RF_PAPE |
+		((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE) <<
+		 FPGA0_RF_BD_CTRL_SHIFT);
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+	/* 0x860[6:5]= 00 - why? - this sets antenna B */
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66F60210);
+
+	priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A,
+						  RF6052_REG_MODE_AG);
+
+	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+	if (!macpower) {
+		if (priv->ep_tx_normal_queue)
+			val8 = TX_PAGE_NUM_NORM_PQ;
+		else
+			val8 = 0;
+
+		rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8);
+
+		val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD;
+
+		if (priv->ep_tx_high_queue)
+			val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT);
+		if (priv->ep_tx_low_queue)
+			val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT);
+
+		rtl8xxxu_write32(priv, REG_RQPN, val32);
+
+		/*
+		 * Set TX buffer boundary
+		 */
+		val8 = TX_TOTAL_PAGE_NUM + 1;
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8);
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8);
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8);
+		rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8);
+		rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8);
+	}
+
+	ret = rtl8xxxu_init_queue_priority(priv);
+	dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	/*
+	 * Set RX page boundary
+	 */
+	rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff);
+	/*
+	 * Transfer page size is always 128
+	 */
+	val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) |
+		(PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT);
+	rtl8xxxu_write8(priv, REG_PBP, val8);
+
+	/*
+	 * Unit in 8 bytes, not obvious what it is used for
+	 */
+	rtl8xxxu_write8(priv, REG_RX_DRVINFO_SZ, 4);
+
+	/*
+	 * Enable all interrupts - not obvious USB needs to do this
+	 */
+	rtl8xxxu_write32(priv, REG_HISR, 0xffffffff);
+	rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
+
+	rtl8xxxu_set_mac(priv);
+	rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION);
+
+	/*
+	 * Configure initial WMAC settings
+	 */
+	val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST |
+		/* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */
+		RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL |
+		RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC;
+	rtl8xxxu_write32(priv, REG_RCR, val32);
+
+	/*
+	 * Accept all multicast
+	 */
+	rtl8xxxu_write32(priv, REG_MAR, 0xffffffff);
+	rtl8xxxu_write32(priv, REG_MAR + 4, 0xffffffff);
+
+	/*
+	 * Init adaptive controls
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
+	val32 |= RESPONSE_RATE_RRSR_CCK_ONLY_1M;
+	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+	/* CCK = 0x0a, OFDM = 0x10 */
+#if 0
+	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
+#else
+	rtl8xxxu_set_spec_sifs(priv, 0x10, 0x10);
+#endif
+	rtl8xxxu_set_retry(priv, 0x30, 0x30);
+	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
+
+	/*
+	 * Init EDCA
+	 */
+	rtl8xxxu_write16(priv, REG_MAC_SPEC_SIFS, 0x100a);
+
+	/* Set CCK SIFS */
+	rtl8xxxu_write16(priv, REG_SIFS_CCK, 0x100a);
+
+	/* Set OFDM SIFS */
+	rtl8xxxu_write16(priv, REG_SIFS_OFDM, 0x100a);
+
+	/* TXOP */
+	rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, 0x005ea42b);
+	rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, 0x0000a44f);
+	rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, 0x005ea324);
+	rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, 0x002fa226);
+
+	/* Set data auto rate fallback retry count */
+	rtl8xxxu_write32(priv, REG_DARFRC, 0x00000000);
+	rtl8xxxu_write32(priv, REG_DARFRC + 4, 0x10080404);
+	rtl8xxxu_write32(priv, REG_RARFRC, 0x04030201);
+	rtl8xxxu_write32(priv, REG_RARFRC + 4, 0x08070605);
+
+	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL);
+	val8 |= FWHW_TXQ_CTRL_AMPDU_RETRY;
+	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, val8);
+
+	/*  Set ACK timeout */
+	rtl8xxxu_write8(priv, REG_ACKTO, 0x40);
+
+	/*
+	 * Initialize beacon parameters
+	 */
+	val16 = BEACON_DISABLE_TSF_UPDATE | (BEACON_DISABLE_TSF_UPDATE << 8);
+	rtl8xxxu_write16(priv, REG_BEACON_CTRL, val16);
+	rtl8xxxu_write16(priv, REG_TBTT_PROHIBIT, 0x6404);
+	rtl8xxxu_write8(priv, REG_DRIVER_EARLY_INT, DRIVER_EARLY_INT_TIME);
+	rtl8xxxu_write8(priv, REG_BEACON_DMA_TIME, BEACON_DMA_ATIME_INT_TIME);
+	rtl8xxxu_write16(priv, REG_BEACON_TCFG, 0x660F);
+
+	/*
+	 * Enable CCK and OFDM block
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 |= (FPGA_RF_MODE_CCK | FPGA_RF_MODE_OFDM);
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	/*
+	 * Invalidate all CAM entries - bit 30 is undocumented
+	 */
+	rtl8xxxu_write32(priv, REG_CAM_CMD, CAM_CMD_POLLING | BIT(30));
+
+	/*
+	 * Start out with default power levels for channel 6, 20MHz
+	 */
+	rtl8723a_set_tx_power(priv, 1, false);
+
+	/* Let the 8051 take control of antenna setting */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 |= LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+	rtl8xxxu_write8(priv, REG_HWSEQ_CTRL, 0xff);
+
+	/* Disable BAR - not sure if this has any effect on USB */
+	rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+	rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0);
+
+#if 0
+	/*
+	 * From 8192cu driver
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+	val32 &= ~BIT(6);
+	val32 |= BIT(5);
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+#endif
+
+	/*
+	 * Not sure if we should get into this at all
+	 */
+	if (priv->iqk_initialized) {
+		rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+				      priv->bb_recovery_backup,
+				      RTL8XXXU_BB_REGS);
+	} else {
+		rtl8723a_phy_iq_calibrate(priv);
+		priv->iqk_initialized = true;
+	}
+
+	/*
+	 * This should enable thermal meter
+	 */
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60);
+
+	rtl8723a_phy_lc_calibrate(priv);
+
+	/* fix USB interface interference issue */
+	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+	rtl8xxxu_write8(priv, 0xfe41, 0x8d);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+	rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320);
+
+	/* Solve too many protocol error on USB bus */
+	/* Can't do this for 8188/8192 UMC A cut parts */
+	rtl8xxxu_write8(priv, 0xfe40, 0xe6);
+	rtl8xxxu_write8(priv, 0xfe41, 0x94);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+	rtl8xxxu_write8(priv, 0xfe41, 0x19);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe5);
+	rtl8xxxu_write8(priv, 0xfe41, 0x91);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe2);
+	rtl8xxxu_write8(priv, 0xfe41, 0x81);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+#if 0
+	/* Init BT hw config. */
+	rtl8723a_init_bt(priv);
+#endif
+
+	/*
+	 * Not sure if we really need to save these parameters, but the
+	 * vendor driver does
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+	if (val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)
+		priv->path_a_hi_power = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	priv->path_a_rf_paths = val32 & OFDM_RF_PATH_RX_MASK;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1);
+	priv->path_a_ig_value = val32 & OFDM0_X_AGC_CORE1_IGI_MASK;
+
+	/* Set NAV_UPPER to 30000us */
+	val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT);
+	rtl8xxxu_write8(priv, REG_NAV_UPPER, val8);
+
+	/*
+	 * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test,
+	 * but we need to fin root cause.
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	if ((val32 & 0xff000000) != 0x83000000) {
+		val32 |= FPGA_RF_MODE_CCK;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL);
+	val32 |= FWHW_TXQ_CTRL_XMIT_MGMT_ACK;
+	/* ack for xmit mgmt frames. */
+	rtl8xxxu_write32(priv, REG_FWHW_TXQ_CTRL, val32);
+
+exit:
+	return ret;
+}
+
+static void rtl8xxxu_disable_device(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	rtl8xxxu_power_off(priv);
+}
+
+static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv,
+			       struct ieee80211_key_conf *key, const u8 *mac)
+{
+	u32 cmd, val32, addr, ctrl;
+	int j, i, tmp_debug;
+
+	tmp_debug = rtl8xxxu_debug;
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_KEY)
+		rtl8xxxu_debug |= RTL8XXXU_DEBUG_REG_WRITE;
+
+	addr = key->keyidx << CAM_CMD_KEY_SHIFT;
+	ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID;
+
+	for (j = 5; j >= 0; j--) {
+		switch (j) {
+		case 0:
+			val32 = ctrl | (mac[0] << 16) | (mac[1] << 24);
+			break;
+		case 1:
+			val32 = mac[2] | (mac[3] << 8) |
+				(mac[4] << 16) | (mac[5] << 24);
+			break;
+		default:
+			i = (j - 2) << 2;
+			val32 = key->key[i] | (key->key[i + 1] << 8) |
+				key->key[i + 2] << 16 | key->key[i + 3] << 24;
+			break;
+		}
+
+		rtl8xxxu_write32(priv, REG_CAM_WRITE, val32);
+		cmd = CAM_CMD_POLLING | CAM_CMD_WRITE | (addr + j);
+		rtl8xxxu_write32(priv, REG_CAM_CMD, cmd);
+		udelay(100);
+	}
+
+	rtl8xxxu_debug = tmp_debug;
+}
+
+static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif, const u8 *mac)
+{
+}
+
+static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+	val8 &= ~BEACON_DISABLE_TSF_UPDATE;
+	rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+}
+
+static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv,
+				      struct ieee80211_sta *sta)
+{
+	struct h2c_cmd h2c;
+	u32 ramask;
+
+	/* TODO: Set bits 28-31 for rate adaptive id */
+	ramask = (sta->supp_rates[0] & 0xfff) |
+		sta->ht_cap.mcs.rx_mask[0] << 12 |
+		sta->ht_cap.mcs.rx_mask[1] << 20;
+
+	h2c.ramask.cmd = H2C_SET_RATE_MASK;
+	h2c.ramask.mask_lo = cpu_to_le16(ramask & 0xffff);
+	h2c.ramask.mask_hi = cpu_to_le16(ramask >> 16);
+
+	h2c.ramask.arg = 0x80;
+	if (sta->ht_cap.cap &
+	    (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))
+		h2c.ramask.arg |= 0x20;
+
+	dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x\n", __func__,
+		ramask, h2c.ramask.arg);
+	rtl8723a_h2c_cmd(priv, &h2c);
+}
+
+static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
+{
+	u32 val32;
+	u8 rate_idx = 0;
+
+	rate_cfg &= RESPONSE_RATE_BITMAP_ALL;
+
+	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
+	val32 |= rate_cfg;
+	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+	dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__,	rate_cfg);
+
+	while (rate_cfg) {
+		rate_cfg = (rate_cfg >> 1);
+		rate_idx++;
+	}
+	rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx);
+}
+
+static void
+rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			  struct ieee80211_bss_conf *bss_conf, u32 changed)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	struct ieee80211_sta *sta;
+	struct rtl8xxxu_sta_priv *sta_priv;
+	u32 val32;
+#if 0
+	u16 val16;
+#endif
+	u8 val8;
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		struct h2c_cmd h2c;
+
+		dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc);
+
+		memset(&h2c, 0, sizeof(struct h2c_cmd));
+		rtl8xxxu_set_linktype(priv, vif->type);
+
+		if (bss_conf->assoc) {
+			rcu_read_lock();
+			sta = ieee80211_find_sta(vif, bss_conf->bssid);
+			if (!sta) {
+				dev_info(dev, "%s: ASSOC no sta found\n",
+					 __func__);
+				rcu_read_unlock();
+				goto error;
+			}
+
+			if (sta->ht_cap.ht_supported)
+				dev_info(dev, "%s: HT supported\n", __func__);
+			if (sta->vht_cap.vht_supported)
+				dev_info(dev, "%s: VHT supported\n", __func__);
+			rtl8xxxu_update_rate_mask(priv, sta);
+			rcu_read_unlock();
+
+			val32 = rtl8xxxu_read32(priv, REG_RCR);
+			val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON;
+			rtl8xxxu_write32(priv, REG_RCR, val32);
+
+			/* Enable RX of data frames */
+			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
+
+			rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
+
+			rtl8723a_stop_tx_beacon(priv);
+
+			/* joinbss sequence */
+			rtl8xxxu_write16(priv, REG_BCN_PSR_RPT,
+					 0xc000 | bss_conf->aid);
+
+#if 0
+			val16 = rtl8xxxu_read16(priv, REG_CR);
+			val16 |= CR_SW_BEACON_ENABLE;
+			rtl8xxxu_read16(priv, REG_CR, val16);
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 &= ~BEACON_FUNCTION_ENABLE;
+			val8 |= BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
+			if (val8 & BIT(6))
+				recover = true;
+
+			val8 &= ~BIT(6);
+			rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
+
+			/* build fake beacon */
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 |= BEACON_FUNCTION_ENABLE;
+			val8 &= ~BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			if (recover) {
+				val8 = rtl8xxxu_read8(priv,
+						      REG_FWHW_TXQ_CTRL + 2);
+				val8 |= BIT(6);
+				rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2,
+						val8);
+			}
+			val16 = rtl8xxxu_read16(priv, REG_CR);
+			val16 &= ~CR_SW_BEACON_ENABLE;
+			rtl8xxxu_read16(priv, REG_CR, val16);
+#endif
+			h2c.joinbss.data = H2C_JOIN_BSS_CONNECT;
+		} else {
+			val32 = rtl8xxxu_read32(priv, REG_RCR);
+			val32 &= ~(RCR_CHECK_BSSID_MATCH |
+				   RCR_CHECK_BSSID_BEACON);
+			rtl8xxxu_write32(priv, REG_RCR, val32);
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 |= BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			/* Disable RX of data frames */
+			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+			h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT;
+		}
+		h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT;
+		rtl8723a_h2c_cmd(priv, &h2c);
+	}
+
+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+		dev_dbg(dev, "Changed ERP_PREAMBLE: Use short preamble %i\n",
+			bss_conf->use_short_preamble);
+		val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+		if (bss_conf->use_short_preamble)
+			val32 |= RSR_ACK_SHORT_PREAMBLE;
+		else
+			val32 &= ~RSR_ACK_SHORT_PREAMBLE;
+		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+		rcu_read_lock();
+		sta = ieee80211_find_sta(vif, bss_conf->bssid);
+		if (sta) {
+			sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
+			if (bss_conf->use_short_preamble)
+				sta_priv->short_preamble = true;
+			else
+				sta_priv->short_preamble = false;
+		}
+		rcu_read_unlock();
+	}
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		dev_dbg(dev, "Changed ERP_SLOT: short_slot_time %i\n",
+			bss_conf->use_short_slot);
+
+		if (bss_conf->use_short_slot)
+			val8 = 9;
+		else
+			val8 = 20;
+		rtl8xxxu_write8(priv, REG_SLOT, val8);
+	}
+
+	if (changed & BSS_CHANGED_BSSID) {
+		dev_dbg(dev, "Changed BSSID!\n");
+		rtl8xxxu_set_bssid(priv, bss_conf->bssid);
+	}
+
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		dev_dbg(dev, "Changed BASIC_RATES!\n");
+		rtl8xxxu_set_basic_rates(priv, bss_conf->basic_rates);
+	}
+error:
+	return;
+}
+
+static u32 rtl8xxxu_80211_to_rtl_queue(u32 queue)
+{
+	u32 rtlqueue;
+
+	switch (queue) {
+	case IEEE80211_AC_VO:
+		rtlqueue = TXDESC_QUEUE_VO;
+		break;
+	case IEEE80211_AC_VI:
+		rtlqueue = TXDESC_QUEUE_VI;
+		break;
+	case IEEE80211_AC_BE:
+		rtlqueue = TXDESC_QUEUE_BE;
+		break;
+	case IEEE80211_AC_BK:
+		rtlqueue = TXDESC_QUEUE_BK;
+		break;
+	default:
+		rtlqueue = TXDESC_QUEUE_BE;
+	}
+
+	return rtlqueue;
+}
+
+static u32 rtl8xxxu_queue_select(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	u32 queue;
+
+	if (ieee80211_is_mgmt(hdr->frame_control))
+		queue = TXDESC_QUEUE_MGNT;
+	else
+		queue = rtl8xxxu_80211_to_rtl_queue(skb_get_queue_mapping(skb));
+
+	return queue;
+}
+
+static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc)
+{
+	__le16 *ptr = (__le16 *)tx_desc;
+	u16 csum = 0;
+	int i;
+
+	/*
+	 * Clear csum field before calculation, as the csum field is
+	 * in the middle of the struct.
+	 */
+	tx_desc->csum = cpu_to_le16(0);
+
+	for (i = 0; i < (sizeof(struct rtl8xxxu_tx_desc) / sizeof(u16)); i++)
+		csum = csum ^ le16_to_cpu(ptr[i]);
+
+	tx_desc->csum |= cpu_to_le16(csum);
+}
+
+static void rtl8xxxu_tx_complete(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_hw *hw;
+
+	tx_info = IEEE80211_SKB_CB(skb);
+	hw = tx_info->rate_driver_data[0];
+
+	skb_pull(skb, sizeof(struct rtl8xxxu_tx_desc));
+
+	ieee80211_tx_info_clear_status(tx_info);
+	tx_info->status.rates[0].idx = -1;
+	tx_info->status.rates[0].count = 0;
+
+#if 0
+	/*
+	 * Until we figure out how to obtain the info,
+	 * do not fool the stack.
+	 */
+	tx_info->flags |= IEEE80211_TX_STAT_ACK;
+#endif
+
+	ieee80211_tx_status_irqsafe(hw, skb);
+
+	usb_free_urb(urb);
+}
+
+static void rtl8xxxu_dump_action(struct device *dev,
+				 struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
+	u16 cap, timeout;
+
+	if (!(rtl8xxxu_debug & RTL8XXXU_DEBUG_ACTION))
+		return;
+
+	switch (mgmt->u.action.u.addba_resp.action_code) {
+	case WLAN_ACTION_ADDBA_RESP:
+		cap = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+		timeout = le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
+		dev_info(dev, "WLAN_ACTION_ADDBA_RESP: "
+			 "timeout %i, tid %02x, buf_size %02x, policy %02x, "
+			 "status %02x\n",
+			 timeout,
+			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
+			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
+			 (cap >> 1) & 0x1,
+			 le16_to_cpu(mgmt->u.action.u.addba_resp.status));
+		break;
+	case WLAN_ACTION_ADDBA_REQ:
+		cap = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+		timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+		dev_info(dev, "WLAN_ACTION_ADDBA_REQ: "
+			 "timeout %i, tid %02x, buf_size %02x, policy %02x\n",
+			 timeout,
+			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
+			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
+			 (cap >> 1) & 0x1);
+		break;
+	default:
+		dev_info(dev, "action frame %02x\n",
+			 mgmt->u.action.u.addba_resp.action_code);
+		break;
+	}
+}
+
+static void rtl8xxxu_tx(struct ieee80211_hw *hw,
+			struct ieee80211_tx_control *control,
+			struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct rtl8xxxu_tx_desc *tx_desc;
+	struct ieee80211_sta *sta = NULL;
+	struct rtl8xxxu_sta_priv *sta_priv = NULL;
+	struct device *dev = &priv->udev->dev;
+	struct urb *urb;
+	u32 queue, rate;
+	u16 pktlen = skb->len;
+	u16 seq_number;
+	u16 rate_flag = tx_info->control.rates[0].flags;
+	int ret;
+
+	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
+		dev_warn(dev,
+			 "%s: Not enough headroom (%i) for tx descriptor\n",
+			 __func__, skb_headroom(skb));
+		goto error;
+	}
+
+	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
+		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
+			 __func__, skb->len);
+		goto error;
+	}
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb) {
+		dev_warn(dev, "%s: Unable to allocate urb\n", __func__);
+		goto error;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX)
+		dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n",
+			 __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen);
+
+	if (ieee80211_is_action(hdr->frame_control))
+		rtl8xxxu_dump_action(dev, hdr);
+
+	tx_info->rate_driver_data[0] = hw;
+
+	if (control && control->sta) {
+		sta = control->sta;
+		sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
+	}
+
+	tx_desc = (struct rtl8xxxu_tx_desc *)
+		skb_push(skb, sizeof(struct rtl8xxxu_tx_desc));
+
+	memset(tx_desc, 0, sizeof(struct rtl8xxxu_tx_desc));
+	tx_desc->pkt_size = cpu_to_le16(pktlen);
+	tx_desc->pkt_offset = sizeof(struct rtl8xxxu_tx_desc);
+
+	tx_desc->txdw0 =
+		TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT;
+	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+		tx_desc->txdw0 |= TXDESC_BROADMULTICAST;
+
+	queue = rtl8xxxu_queue_select(hw, skb);
+	tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT);
+
+	if (tx_info->control.hw_key) {
+		switch (tx_info->control.hw_key->cipher) {
+		case WLAN_CIPHER_SUITE_WEP40:
+		case WLAN_CIPHER_SUITE_WEP104:
+		case WLAN_CIPHER_SUITE_TKIP:
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_RC4);
+			break;
+		case WLAN_CIPHER_SUITE_CCMP:
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_AES);
+			break;
+		default:
+			break;
+		}
+	}
+
+	seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+	tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT);
+
+	if (rate_flag & IEEE80211_TX_RC_MCS)
+		rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0;
+	else
+		rate = tx_rate->hw_value;
+	tx_desc->txdw5 = cpu_to_le32(rate);
+
+	if (ieee80211_is_data(hdr->frame_control))
+		tx_desc->txdw5 |= cpu_to_le32(0x0001ff00);
+
+	/* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */
+	if (ieee80211_is_data_qos(hdr->frame_control) && sta) {
+		if (sta->ht_cap.ht_supported) {
+			u32 ampdu, val32;
+
+			ampdu = (u32)sta->ht_cap.ampdu_density;
+			val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;
+			tx_desc->txdw2 |= cpu_to_le32(val32);
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE);
+		} else
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
+	} else
+		tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
+
+	if (ieee80211_is_data_qos(hdr->frame_control))
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS);
+	if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ||
+	    (sta_priv && sta_priv->short_preamble))
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_SHORT_PREAMBLE);
+	if (rate_flag & IEEE80211_TX_RC_SHORT_GI ||
+	    (ieee80211_is_data_qos(hdr->frame_control) &&
+	     sta && sta->ht_cap.cap &
+	     (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) {
+		tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI);
+	}
+	if (ieee80211_is_mgmt(hdr->frame_control)) {
+		tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE);
+		tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT);
+		tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE);
+	}
+
+	if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
+		/* Use RTS rate 24M - does the mac80211 tell us which to use? */
+		tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE);
+	}
+
+	rtl8xxxu_calc_tx_desc_csum(tx_desc);
+
+	usb_fill_bulk_urb(urb, priv->udev, priv->pipe_out[queue], skb->data,
+			  skb->len, rtl8xxxu_tx_complete, skb);
+
+	usb_anchor_urb(urb, &priv->tx_anchor);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		goto error;
+	}
+	return;
+error:
+	dev_kfree_skb(skb);
+}
+
+static void rtl8xxxu_rx_complete(struct urb *urb)
+{
+	struct rtl8xxxu_rx_urb *rx_urb =
+		container_of(urb, struct rtl8xxxu_rx_urb, urb);
+	struct ieee80211_hw *hw = rx_urb->hw;
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data;
+	struct rtl8723au_phy_stats *phy_stats;
+	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_mgmt *mgmt;
+	struct device *dev = &priv->udev->dev;
+	__le32 *_rx_desc_le = (__le32 *)skb->data;
+	u32 *_rx_desc = (u32 *)skb->data;
+	int cnt, len, drvinfo_sz, desc_shift, i, ret;
+
+	for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++)
+		_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
+
+	cnt = rx_desc->frag;
+	len = rx_desc->pktlen;
+	drvinfo_sz = rx_desc->drvinfo_sz * 8;
+	desc_shift = rx_desc->shift;
+	skb_put(skb, urb->actual_length);
+
+	if (urb->status == 0) {
+		skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc));
+		phy_stats = (struct rtl8723au_phy_stats *)skb->data;
+
+		skb_pull(skb, drvinfo_sz + desc_shift);
+
+		mgmt = (struct ieee80211_mgmt *)skb->data;
+
+		memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+		/*
+		 * Note this is valid for CCK rates only - FIXME
+		 */
+		if (rx_desc->phy_stats) {
+			u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
+
+			switch (cck_agc_rpt & 0xc0) {
+			case 0xc0:
+				rx_status->signal = -46 - (cck_agc_rpt & 0x3e);
+				break;
+			case 0x80:
+				rx_status->signal = -26 - (cck_agc_rpt & 0x3e);
+				break;
+			case 0x40:
+				rx_status->signal = -12 - (cck_agc_rpt & 0x3e);
+				break;
+			case 0x00:
+				rx_status->signal = 16 - (cck_agc_rpt & 0x3e);
+				break;
+			}
+		}
+
+		rx_status->freq = hw->conf.chandef.chan->center_freq;
+		rx_status->band = hw->conf.chandef.chan->band;
+
+		rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
+
+		if (!rx_desc->swdec)
+			rx_status->flag |= RX_FLAG_DECRYPTED;
+		if (rx_desc->crc32)
+			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+		if (rx_desc->bw)
+			rx_status->flag |= RX_FLAG_40MHZ;
+
+		if (rx_desc->rxht) {
+			rx_status->flag |= RX_FLAG_HT;
+			rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
+		} else {
+			rx_status->rate_idx = rx_desc->rxmcs;
+		}
+
+		ieee80211_rx_irqsafe(hw, skb);
+		skb = NULL;
+		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+		if (ret) {
+			dev_warn(dev, "%s: Unable to allocate skb\n", __func__);
+			goto cleanup;
+		}
+	} else {
+		dev_dbg(dev, "%s: status %i\n",	__func__, urb->status);
+		goto cleanup;
+	}
+	return;
+
+cleanup:
+	usb_free_urb(urb);
+	dev_kfree_skb(skb);
+	return;
+}
+
+static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb)
+{
+	struct sk_buff *skb;
+	int skb_size;
+	int ret;
+
+	skb_size = sizeof(struct rtl8xxxu_rx_desc) + RTL_RX_BUFFER_SIZE;
+	skb = dev_alloc_skb(skb_size);
+	if (!skb)
+		return -ENOMEM;
+
+	memset(skb->data, 0, sizeof(struct rtl8xxxu_rx_desc));
+	usb_fill_bulk_urb(&rx_urb->urb, priv->udev, priv->pipe_in, skb->data,
+			  skb_size, rtl8xxxu_rx_complete, skb);
+	usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor);
+	ret = usb_submit_urb(&rx_urb->urb, GFP_ATOMIC);
+	if (ret)
+		usb_unanchor_urb(&rx_urb->urb);
+	return ret;
+}
+
+static void rtl8xxxu_int_complete(struct urb *urb)
+{
+	struct rtl8xxxu_priv *priv = (struct rtl8xxxu_priv *)urb->context;
+	struct device *dev = &priv->udev->dev;
+	int ret;
+
+	dev_dbg(dev, "%s: status %i\n", __func__, urb->status);
+	if (urb->status == 0) {
+		usb_anchor_urb(urb, &priv->int_anchor);
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret)
+			usb_unanchor_urb(urb);
+	} else {
+		dev_info(dev, "%s: Error %i\n", __func__, urb->status);
+	}
+}
+
+
+static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct urb *urb;
+	u32 val32;
+	int ret;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	usb_fill_int_urb(urb, priv->udev, priv->pipe_interrupt,
+			 priv->int_buf, USB_INTR_CONTENT_LENGTH,
+			 rtl8xxxu_int_complete, priv, 1);
+	usb_anchor_urb(urb, &priv->int_anchor);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		goto error;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_USB_HIMR);
+	val32 |= USB_HIMR_CPWM;
+	rtl8xxxu_write32(priv, REG_USB_HIMR, val32);
+
+error:
+	return ret;
+}
+
+static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	int ret;
+	u8 val8;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		rtl8723a_stop_tx_beacon(priv);
+
+		val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+		val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE |
+			BEACON_DISABLE_TSF_UPDATE;
+		rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+		ret = 0;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	rtl8xxxu_set_linktype(priv, vif->type);
+
+	return ret;
+}
+
+static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	dev_dbg(&priv->udev->dev, "%s\n", __func__);
+}
+
+static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u16 val16;
+	int ret = 0, channel;
+	bool ht40;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
+		dev_info(dev,
+			 "%s: channel: %i (changed %08x chandef.width %02x)\n",
+			 __func__, hw->conf.chandef.chan->hw_value,
+			 changed, hw->conf.chandef.width);
+
+	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
+		val16 = ((hw->conf.long_frame_max_tx_count <<
+			  RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) |
+			((hw->conf.short_frame_max_tx_count <<
+			  RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK);
+		rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		switch (hw->conf.chandef.width) {
+		case NL80211_CHAN_WIDTH_20_NOHT:
+		case NL80211_CHAN_WIDTH_20:
+			ht40 = false;
+			break;
+		case NL80211_CHAN_WIDTH_40:
+			ht40 = true;
+			break;
+		default:
+			ret = -ENOTSUPP;
+			goto exit;
+		}
+
+		channel = hw->conf.chandef.chan->hw_value;
+
+		rtl8723a_set_tx_power(priv, channel, ht40);
+
+		rtl8723au_config_channel(hw);
+	}
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif, u16 queue,
+			    const struct ieee80211_tx_queue_params *param)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u32 val32;
+	u8 aifs, acm_ctrl, acm_bit;
+
+	aifs = param->aifs;
+
+	val32 = aifs |
+		fls(param->cw_min) << EDCA_PARAM_ECW_MIN_SHIFT |
+		fls(param->cw_max) << EDCA_PARAM_ECW_MAX_SHIFT |
+		(u32)param->txop << EDCA_PARAM_TXOP_SHIFT;
+
+	acm_ctrl = rtl8xxxu_read8(priv, REG_ACM_HW_CTRL);
+	dev_dbg(dev,
+		"%s: IEEE80211 queue %02x val %08x, acm %i, acm_ctrl %02x\n",
+		__func__, queue, val32, param->acm, acm_ctrl);
+
+	switch (queue) {
+	case IEEE80211_AC_VO:
+		acm_bit = ACM_HW_CTRL_VO;
+		rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, val32);
+		break;
+	case IEEE80211_AC_VI:
+		acm_bit = ACM_HW_CTRL_VI;
+		rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, val32);
+		break;
+	case IEEE80211_AC_BE:
+		acm_bit = ACM_HW_CTRL_BE;
+		rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, val32);
+		break;
+	case IEEE80211_AC_BK:
+		acm_bit = ACM_HW_CTRL_BK;
+		rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, val32);
+		break;
+	default:
+		acm_bit = 0;
+		break;
+	}
+
+	if (param->acm)
+		acm_ctrl |= acm_bit;
+	else
+		acm_ctrl &= ~acm_bit;
+	rtl8xxxu_write8(priv, REG_ACM_HW_CTRL, acm_ctrl);
+
+	return 0;
+}
+
+static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw,
+				      unsigned int changed_flags,
+				      unsigned int *total_flags, u64 multicast)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n",
+		__func__, changed_flags, *total_flags);
+
+	*total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC);
+}
+
+static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts)
+{
+	if (rts > 2347)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			    struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta,
+			    struct ieee80211_key_conf *key)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u8 mac_addr[ETH_ALEN];
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int retval = -EOPNOTSUPP;
+
+	dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n",
+		__func__, cmd, key->cipher, key->keyidx);
+
+	if (vif->type != NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
+
+	if (key->keyidx > 3)
+		return -EOPNOTSUPP;
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
+		dev_dbg(dev, "%s: pairwise key\n", __func__);
+		ether_addr_copy(mac_addr, sta->addr);
+	} else {
+		dev_dbg(dev, "%s: group key\n", __func__);
+		eth_broadcast_addr(mac_addr);
+	}
+
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= CR_SECURITY_ENABLE;
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	val8 = SEC_CFG_TX_SEC_ENABLE | SEC_CFG_TXBC_USE_DEFKEY |
+		SEC_CFG_RX_SEC_ENABLE | SEC_CFG_RXBC_USE_DEFKEY;
+	val8 |= SEC_CFG_TX_USE_DEFKEY | SEC_CFG_RX_USE_DEFKEY;
+	rtl8xxxu_write8(priv, REG_SECURITY_CFG, val8);
+
+	switch (cmd) {
+	case SET_KEY:
+		/*
+		 * This is a bit of a hack - the lower bits of the cipher
+		 * suite selector happens to match the cipher index in the
+		 * CAM
+		 */
+		key->hw_key_idx = key->keyidx;
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		rtl8xxxu_cam_write(priv, key, mac_addr);
+		retval = 0;
+		break;
+	case DISABLE_KEY:
+		rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000);
+		val32 = CAM_CMD_POLLING | CAM_CMD_WRITE |
+			key->keyidx << CAM_CMD_KEY_SHIFT;
+		rtl8xxxu_write32(priv, REG_CAM_CMD, val32);
+		retval = 0;
+		break;
+	default:
+		dev_warn(dev, "%s: Unsupported command %02x\n", __func__, cmd);
+	}
+
+	return retval;
+}
+
+static int
+rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		      enum ieee80211_ampdu_mlme_action action,
+		      struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u8 ampdu_factor, ampdu_density;
+
+	switch (action) {
+	case IEEE80211_AMPDU_TX_START:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_START\n", __func__);
+		ampdu_factor = sta->ht_cap.ampdu_factor;
+		ampdu_density = sta->ht_cap.ampdu_density;
+		rtl8xxxu_set_ampdu_factor(priv, ampdu_factor);
+		rtl8xxxu_set_ampdu_min_space(priv, ampdu_density);
+		dev_dbg(dev,
+			"Changed HT: ampdu_factor %02x, ampdu_density %02x\n",
+			ampdu_factor, ampdu_density);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);
+		rtl8xxxu_set_ampdu_factor(priv, 0);
+		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",
+			 __func__);
+		rtl8xxxu_set_ampdu_factor(priv, 0);
+		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		break;
+	case IEEE80211_AMPDU_RX_START:
+		dev_info(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		dev_info(dev, "%s: IEEE80211_AMPDU_RX_STOP\n", __func__);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int rtl8xxxu_sta_add(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta)
+{
+	struct rtl8xxxu_sta_priv *sta_priv;
+
+	sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
+
+	sta_priv->short_preamble = false;
+	return 0;
+};
+
+static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_sta *sta)
+{
+	return 0;
+};
+
+static int rtl8xxxu_start(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct rtl8xxxu_rx_urb *rx_urb;
+	int ret, i;
+
+	ret = 0;
+
+	init_usb_anchor(&priv->rx_anchor);
+	init_usb_anchor(&priv->tx_anchor);
+	init_usb_anchor(&priv->int_anchor);
+
+	rtl8723a_enable_rf(priv);
+	ret = rtl8xxxu_submit_int_urb(hw);
+	if (ret)
+		goto exit;
+
+	for (i = 0; i < 32; i++) {
+		rx_urb = kmalloc(sizeof(struct rtl8xxxu_rx_urb), GFP_ATOMIC);
+		if (!rx_urb) {
+			if (!i)
+				ret = -ENOMEM;
+
+			goto exit;
+		}
+		usb_init_urb(&rx_urb->urb);
+		rx_urb->hw = hw;
+
+		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+	}
+exit:
+	/*
+	 * Disable all data frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+	/*
+	 * Accept all mgmt frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff);
+
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e);
+
+	return ret;
+}
+
+static void rtl8xxxu_stop(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000);
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+
+	usb_kill_anchored_urbs(&priv->rx_anchor);
+	usb_kill_anchored_urbs(&priv->tx_anchor);
+	usb_kill_anchored_urbs(&priv->int_anchor);
+
+	rtl8723a_disable_rf(priv);
+
+	/*
+	 * Disable interrupts
+	 */
+	rtl8xxxu_write32(priv, REG_USB_HIMR, 0);
+}
+
+static const struct ieee80211_ops rtl8xxxu_ops = {
+	.tx = rtl8xxxu_tx,
+	.add_interface = rtl8xxxu_add_interface,
+	.remove_interface = rtl8xxxu_remove_interface,
+	.config = rtl8xxxu_config,
+	.conf_tx = rtl8xxxu_conf_tx,
+	.bss_info_changed = rtl8xxxu_bss_info_changed,
+	.configure_filter = rtl8xxxu_configure_filter,
+	.set_rts_threshold = rtl8xxxu_set_rts_threshold,
+	.start = rtl8xxxu_start,
+	.stop = rtl8xxxu_stop,
+	.sw_scan_start = rtl8xxxu_sw_scan_start,
+	.sw_scan_complete = rtl8xxxu_sw_scan_complete,
+	.set_key = rtl8xxxu_set_key,
+	.ampdu_action = rtl8xxxu_ampdu_action,
+	.sta_add = rtl8xxxu_sta_add,
+	.sta_remove = rtl8xxxu_sta_remove,
+};
+
+static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv,
+			      struct usb_interface *interface)
+{
+	struct usb_interface_descriptor *interface_desc;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct device *dev = &priv->udev->dev;
+	int i, j = 0, endpoints;
+	u8 dir, xtype, num;
+	int ret = 0;
+
+	host_interface = &interface->altsetting[0];
+	interface_desc = &host_interface->desc;
+	endpoints = interface_desc->bNumEndpoints;
+
+	for (i = 0; i < endpoints; i++) {
+		endpoint = &host_interface->endpoint[i].desc;
+
+		dir = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		num = usb_endpoint_num(endpoint);
+		xtype = usb_endpoint_type(endpoint);
+		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+			dev_dbg(dev,
+				"%s: endpoint: dir %02x, # %02x, type %02x\n",
+				__func__, dir, num, xtype);
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: in endpoint num %i\n",
+					__func__, num);
+
+			if (priv->pipe_in) {
+				dev_warn(dev,
+					 "%s: Too many IN pipes\n", __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			priv->pipe_in =	usb_rcvbulkpipe(priv->udev, num);
+		}
+
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_int(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: interrupt endpoint num %i\n",
+					__func__, num);
+
+			if (priv->pipe_interrupt) {
+				dev_warn(dev, "%s: Too many INTERRUPT pipes\n",
+					 __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			priv->pipe_interrupt = usb_rcvintpipe(priv->udev, num);
+		}
+
+		if (usb_endpoint_dir_out(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: out endpoint num %i\n",
+					__func__, num);
+			if (j >= RTL8XXXU_OUT_ENDPOINTS) {
+				dev_warn(dev,
+					 "%s: Too many OUT pipes\n", __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+			priv->out_ep[j++] = num;
+		}
+	}
+exit:
+	priv->nr_out_eps = j;
+	return ret;
+}
+
+static int rtl8xxxu_probe(struct usb_interface *interface,
+			  const struct usb_device_id *id)
+{
+	struct rtl8xxxu_priv *priv;
+	struct ieee80211_hw *hw;
+	struct usb_device *udev;
+	struct ieee80211_supported_band *sband;
+	int ret = 0;
+	int untested = 1;
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+
+	switch (id->idVendor) {
+	case USB_VENDOR_ID_REALTEK:
+		switch(id->idProduct) {
+		case 0x1724:
+		case 0x8176:
+		case 0x8178:
+		case 0x817f:
+			untested = 0;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (untested) {
+		rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE;
+		dev_info(&udev->dev,
+			 "This Realtek USB WiFi dongle (0x%04x:0x%04x) is untested!\n",
+			 id->idVendor, id->idProduct);
+		dev_info(&udev->dev,
+			 "Please report results to Jes.Sorensen@gmail.com\n");
+	}
+
+	hw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), &rtl8xxxu_ops);
+	if (!hw) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	priv = hw->priv;
+	priv->hw = hw;
+	priv->udev = udev;
+	priv->fops = (struct rtl8xxxu_fileops *)id->driver_info;
+	mutex_init(&priv->usb_buf_mutex);
+	mutex_init(&priv->h2c_mutex);
+
+	usb_set_intfdata(interface, hw);
+
+	ret = rtl8xxxu_parse_usb(priv, interface);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_identify_chip(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to identify chip\n");
+		goto exit;
+	}
+
+	ret = rtl8xxxu_read_efuse(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to read EFuse\n");
+		goto exit;
+	}
+
+	ret = priv->fops->parse_efuse(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to parse EFuse\n");
+		goto exit;
+	}
+
+	rtl8xxxu_print_chipinfo(priv);
+
+	ret = priv->fops->load_firmware(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to load firmware\n");
+		goto exit;
+	}
+
+	ret = rtl8xxxu_init_device(hw);
+
+	hw->wiphy->max_scan_ssids = 1;
+	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	hw->queues = 4;
+
+	sband = &rtl8xxxu_supported_band;
+	sband->ht_cap.ht_supported = true;
+	sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+	sband->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+	sband->ht_cap.cap = /* IEEE80211_HT_CAP_SUP_WIDTH_20_40 | */
+		IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40;
+	memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs));
+	sband->ht_cap.mcs.rx_mask[0] = 0xff;
+	sband->ht_cap.mcs.rx_mask[4] = 0x01;
+	if (priv->rf_paths > 1) {
+		sband->ht_cap.mcs.rx_mask[1] = 0xff;
+		sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+	}
+	sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+	hw->wiphy->rts_threshold = 2347;
+
+	SET_IEEE80211_DEV(priv->hw, &interface->dev);
+	SET_IEEE80211_PERM_ADDR(hw, priv->mac_addr);
+
+	hw->extra_tx_headroom = sizeof(struct rtl8xxxu_tx_desc);
+	hw->sta_data_size = sizeof(struct rtl8xxxu_sta_priv);
+	ieee80211_hw_set(hw, SIGNAL_DBM);
+	/*
+	 * The firmware handles rate control
+	 */
+	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
+	ret = ieee80211_register_hw(priv->hw);
+	if (ret) {
+		dev_err(&udev->dev, "%s: Failed to register: %i\n",
+			__func__, ret);
+		goto exit;
+	}
+
+exit:
+	if (ret < 0)
+		usb_put_dev(udev);
+	return ret;
+}
+
+static void rtl8xxxu_disconnect(struct usb_interface *interface)
+{
+	struct rtl8xxxu_priv *priv;
+	struct ieee80211_hw *hw;
+
+	hw = usb_get_intfdata(interface);
+	priv = hw->priv;
+
+	rtl8xxxu_disable_device(hw);
+	usb_set_intfdata(interface, NULL);
+
+	dev_info(&priv->udev->dev, "disconnecting\n");
+
+	ieee80211_unregister_hw(hw);
+
+	kfree(priv->fw_data);
+	mutex_destroy(&priv->usb_buf_mutex);
+	mutex_destroy(&priv->h2c_mutex);
+
+	usb_put_dev(priv->udev);
+	ieee80211_free_hw(hw);
+}
+
+static struct rtl8xxxu_fileops rtl8723au_fops = {
+	.parse_efuse = rtl8723au_parse_efuse,
+	.load_firmware = rtl8723au_load_firmware,
+	.power_on = rtl8723au_power_on,
+	.writeN = rtl8xxxu_writeN,
+};
+
+static struct rtl8xxxu_fileops rtl8192cu_fops = {
+	.parse_efuse = rtl8192cu_parse_efuse,
+	.load_firmware = rtl8192cu_load_firmware,
+	.power_on = rtl8192cu_power_on,
+	.writeN = rtl8xxxu_slow_writeN,
+};
+
+static struct usb_device_id dev_table[] = {
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8178, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+#ifdef CONFIG_RTL8XXXU_UNTESTED
+/* Currently untested 8188 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8177, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x1058, 0x0631, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x094c, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1102, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ba, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1e1e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x5088, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0052, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x005c, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0eb0, 0x9071, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x103c, 0x1629, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x13d3, 0x3357, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x4902, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xed17, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x648b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0090, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4856, 0x0091, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7811, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffa, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff8, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffb, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffc, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x1201, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+/* Currently untested 8192 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0950, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2102, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2103, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x341f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe035, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ab, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0061, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0070, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0789, 0x016d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07aa, 0x0056, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8178, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9021, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0xf001, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x2e2e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0019, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0020, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3307, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3309, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x624d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0100, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0091, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+#endif
+{ }
+};
+
+static struct usb_driver rtl8xxxu_driver = {
+	.name = DRIVER_NAME,
+	.probe = rtl8xxxu_probe,
+	.disconnect = rtl8xxxu_disconnect,
+	.id_table = dev_table,
+	.disable_hub_initiated_lpm = 1,
+};
+
+static int __init rtl8xxxu_module_init(void)
+{
+	int res;
+
+	res = usb_register(&rtl8xxxu_driver);
+	if (res < 0)
+		pr_err(DRIVER_NAME ": usb_register() failed (%i)\n", res);
+
+	return res;
+}
+
+static void __exit rtl8xxxu_module_exit(void)
+{
+	usb_deregister(&rtl8xxxu_driver);
+}
+
+
+MODULE_DEVICE_TABLE(usb, dev_table);
+
+module_init(rtl8xxxu_module_init);
+module_exit(rtl8xxxu_module_exit);
diff --git a/drivers/net/wireless/rtl8xxxu.h b/drivers/net/wireless/rtl8xxxu.h
new file mode 100644
index 0000000..ad499f9
--- /dev/null
+++ b/drivers/net/wireless/rtl8xxxu.h
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Register definitions taken from original Realtek rtl8723au driver
+ */
+
+#include <asm/byteorder.h>
+
+#define RTL8XXXU_DEBUG_REG_WRITE	0x01
+#define RTL8XXXU_DEBUG_REG_READ		0x02
+#define RTL8XXXU_DEBUG_RFREG_WRITE	0x04
+#define RTL8XXXU_DEBUG_RFREG_READ	0x08
+#define RTL8XXXU_DEBUG_CHANNEL		0x10
+#define RTL8XXXU_DEBUG_TX		0x20
+#define RTL8XXXU_DEBUG_TX_DUMP		0x40
+#define RTL8XXXU_DEBUG_RX		0x80
+#define RTL8XXXU_DEBUG_RX_DUMP		0x100
+#define RTL8XXXU_DEBUG_USB		0x200
+#define RTL8XXXU_DEBUG_KEY		0x400
+#define RTL8XXXU_DEBUG_H2C		0x800
+#define RTL8XXXU_DEBUG_ACTION		0x1000
+#define RTL8XXXU_DEBUG_EFUSE		0x2000
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT	500
+#define RTL8XXXU_MAX_REG_POLL		500
+#define	USB_INTR_CONTENT_LENGTH		56
+
+#define RTL8XXXU_OUT_ENDPOINTS		3
+
+#define REALTEK_USB_READ		0xc0
+#define REALTEK_USB_WRITE		0x40
+#define REALTEK_USB_CMD_REQ		0x05
+#define REALTEK_USB_CMD_IDX		0x00
+
+#define TX_TOTAL_PAGE_NUM		0xf8
+/* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */
+#define TX_PAGE_NUM_PUBQ		0xe7
+#define TX_PAGE_NUM_HI_PQ		0x0c
+#define TX_PAGE_NUM_LO_PQ		0x02
+#define TX_PAGE_NUM_NORM_PQ		0x02
+
+#define RTL_FW_PAGE_SIZE		4096
+#define RTL8XXXU_FIRMWARE_POLL_MAX	1000
+
+#define RTL8723A_CHANNEL_GROUPS		3
+#define RTL8723A_MAX_RF_PATHS		2
+#define RF6052_MAX_TX_PWR		0x3f
+
+#define EFUSE_MAP_LEN_8723A		256
+#define EFUSE_MAX_SECTION_8723A		32
+#define EFUSE_REAL_CONTENT_LEN_8723A	512
+#define EFUSE_BT_MAP_LEN_8723A		1024
+#define EFUSE_MAX_WORD_UNIT		4
+
+struct rtl8xxxu_rx_desc {
+	u32 pktlen:14;
+	u32 crc32:1;
+	u32 icverr:1;
+	u32 drvinfo_sz:4;
+	u32 security:3;
+	u32 qos:1;
+	u32 shift:2;
+	u32 phy_stats:1;
+	u32 swdec:1;
+	u32 ls:1;
+	u32 fs:1;
+	u32 eor:1;
+	u32 own:1;
+
+	u32 macid:5;
+	u32 tid:4;
+	u32 hwrsvd:4;
+	u32 amsdu:1;
+	u32 paggr:1;
+	u32 faggr:1;
+	u32 a1fit:4;
+	u32 a2fit:4;
+	u32 pam:1;
+	u32 pwr:1;
+	u32 md:1;
+	u32 mf:1;
+	u32 type:2;
+	u32 mc:1;
+	u32 bc:1;
+
+	u32 seq:12;
+	u32 frag:4;
+	u32 nextpktlen:14;
+	u32 nextind:1;
+	u32 reserved0:1;
+
+	u32 rxmcs:6;
+	u32 rxht:1;
+	u32 gf:1;
+	u32 splcp:1;
+	u32 bw:1;
+	u32 htc:1;
+	u32 eosp:1;
+	u32 bssidfit:2;
+	u32 reserved1:16;
+	u32 unicastwake:1;
+	u32 magicwake:1;
+
+	u32 pattern0match:1;
+	u32 pattern1match:1;
+	u32 pattern2match:1;
+	u32 pattern3match:1;
+	u32 pattern4match:1;
+	u32 pattern5match:1;
+	u32 pattern6match:1;
+	u32 pattern7match:1;
+	u32 pattern8match:1;
+	u32 pattern9match:1;
+	u32 patternamatch:1;
+	u32 patternbmatch:1;
+	u32 patterncmatch:1;
+	u32 reserved2:19;
+
+	__le32 tsfl;
+#if 0
+	u32 bassn:12;
+	u32 bavld:1;
+	u32 reserved3:19;
+#endif
+};
+
+struct rtl8xxxu_tx_desc {
+	__le16 pkt_size;
+	u8 pkt_offset;
+	u8 txdw0;
+	__le32 txdw1;
+	__le32 txdw2;
+	__le32 txdw3;
+	__le32 txdw4;
+	__le32 txdw5;
+	__le32 txdw6;
+	__le16 csum;
+	__le16 txdw7;
+};
+
+/*  CCK Rates, TxHT = 0 */
+#define DESC_RATE_1M			0x00
+#define DESC_RATE_2M			0x01
+#define DESC_RATE_5_5M			0x02
+#define DESC_RATE_11M			0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC_RATE_6M			0x04
+#define DESC_RATE_9M			0x05
+#define DESC_RATE_12M			0x06
+#define DESC_RATE_18M			0x07
+#define DESC_RATE_24M			0x08
+#define DESC_RATE_36M			0x09
+#define DESC_RATE_48M			0x0a
+#define DESC_RATE_54M			0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC_RATE_MCS0			0x0c
+#define DESC_RATE_MCS1			0x0d
+#define DESC_RATE_MCS2			0x0e
+#define DESC_RATE_MCS3			0x0f
+#define DESC_RATE_MCS4			0x10
+#define DESC_RATE_MCS5			0x11
+#define DESC_RATE_MCS6			0x12
+#define DESC_RATE_MCS7			0x13
+#define DESC_RATE_MCS8			0x14
+#define DESC_RATE_MCS9			0x15
+#define DESC_RATE_MCS10			0x16
+#define DESC_RATE_MCS11			0x17
+#define DESC_RATE_MCS12			0x18
+#define DESC_RATE_MCS13			0x19
+#define DESC_RATE_MCS14			0x1a
+#define DESC_RATE_MCS15			0x1b
+#define DESC_RATE_MCS15_SG		0x1c
+#define DESC_RATE_MCS32			0x20
+
+#define TXDESC_OFFSET_SZ		0
+#define TXDESC_OFFSET_SHT		16
+#if 0
+#define TXDESC_BMC			BIT(24)
+#define TXDESC_LSG			BIT(26)
+#define TXDESC_FSG			BIT(27)
+#define TXDESC_OWN			BIT(31)
+#else
+#define TXDESC_BROADMULTICAST		BIT(0)
+#define TXDESC_LAST_SEGMENT		BIT(2)
+#define TXDESC_FIRST_SEGMENT		BIT(3)
+#define TXDESC_OWN			BIT(7)
+#endif
+
+/* Word 1 */
+#define TXDESC_PKT_OFFSET_SZ		0
+#define TXDESC_AGG_ENABLE		BIT(5)
+#define TXDESC_BK			BIT(6)
+#define TXDESC_QUEUE_SHIFT		8
+#define TXDESC_QUEUE_MASK		0x1f00
+#define TXDESC_QUEUE_BK			0x2
+#define TXDESC_QUEUE_BE			0x0
+#define TXDESC_QUEUE_VI			0x5
+#define TXDESC_QUEUE_VO			0x7
+#define TXDESC_QUEUE_BEACON		0x10
+#define TXDESC_QUEUE_HIGH		0x11
+#define TXDESC_QUEUE_MGNT		0x12
+#define TXDESC_QUEUE_CMD		0x13
+#define TXDESC_QUEUE_MAX		(TXDESC_QUEUE_CMD + 1)
+
+#define DESC_RATE_ID_SHIFT		16
+#define DESC_RATE_ID_MASK		0xf
+#define TXDESC_NAVUSEHDR		BIT(20)
+#define TXDESC_SEC_RC4			0x00400000
+#define TXDESC_SEC_AES			0x00c00000
+#define TXDESC_PKT_OFFSET_SHIFT		26
+#define TXDESC_AGG_EN			BIT(29)
+#define TXDESC_HWPC			BIT(31)
+
+/* Word 2 */
+#define TXDESC_ACK_REPORT		BIT(19)
+#define TXDESC_AMPDU_DENSITY_SHIFT	20
+
+/* Word 3 */
+#define TXDESC_SEQ_SHIFT		16
+#define TXDESC_SEQ_MASK			0x0fff0000
+
+/* Word 4 */
+#define TXDESC_QOS			BIT(6)
+#define TXDESC_HW_SEQ_ENABLE		BIT(7)
+#define TXDESC_USE_DRIVER_RATE		BIT(8)
+#define TXDESC_DISABLE_DATA_FB		BIT(10)
+#define TXDESC_CTS_SELF_ENABLE		BIT(11)
+#define TXDESC_RTS_CTS_ENABLE		BIT(12)
+#define TXDESC_HW_RTS_ENABLE		BIT(13)
+#define TXDESC_PRIME_CH_OFF_LOWER	BIT(20)
+#define TXDESC_PRIME_CH_OFF_UPPER	BIT(21)
+#define TXDESC_SHORT_PREAMBLE		BIT(24)
+#define TXDESC_DATA_BW			BIT(25)
+#define TXDESC_RTS_DATA_BW		BIT(27)
+#define TXDESC_RTS_PRIME_CH_OFF_LOWER	BIT(28)
+#define TXDESC_RTS_PRIME_CH_OFF_UPPER	BIT(29)
+
+/* Word 5 */
+#define TXDESC_RTS_RATE_SHIFT		0
+#define TXDESC_RTS_RATE_MASK		0x3f
+#define TXDESC_SHORT_GI			BIT(6)
+#define TXDESC_CCX_TAG			BIT(7)
+#define TXDESC_RETRY_LIMIT_ENABLE	BIT(17)
+#define TXDESC_RETRY_LIMIT_SHIFT	18
+#define TXDESC_RETRY_LIMIT_MASK		0x00fc0000
+
+/* Word 6 */
+#define TXDESC_MAX_AGG_SHIFT		11
+
+struct phy_rx_agc_info {
+#ifdef __LITTLE_ENDIAN
+	u8	gain:7, trsw:1;
+#else
+	u8	trsw:1, gain:7;
+#endif
+};
+
+struct rtl8723au_phy_stats {
+	struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS];
+	u8	ch_corr[RTL8723A_MAX_RF_PATHS];
+	u8	cck_sig_qual_ofdm_pwdb_all;
+	u8	cck_agc_rpt_ofdm_cfosho_a;
+	u8	cck_rpt_b_ofdm_cfosho_b;
+	u8	reserved_1;
+	u8	noise_power_db_msb;
+	u8	path_cfotail[RTL8723A_MAX_RF_PATHS];
+	u8	pcts_mask[RTL8723A_MAX_RF_PATHS];
+	s8	stream_rxevm[RTL8723A_MAX_RF_PATHS];
+	u8	path_rxsnr[RTL8723A_MAX_RF_PATHS];
+	u8	noise_power_db_lsb;
+	u8	reserved_2[3];
+	u8	stream_csi[RTL8723A_MAX_RF_PATHS];
+	u8	stream_target_csi[RTL8723A_MAX_RF_PATHS];
+	s8	sig_evm;
+	u8	reserved_3;
+
+#ifdef __LITTLE_ENDIAN
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+	u8	sgi_en:1;
+	u8	rxsc:2;
+	u8	idle_long:1;
+	u8	r_ant_train_en:1;
+	u8	antenna_select_b:1;
+	u8	antenna_select:1;
+#else	/*  _BIG_ENDIAN_ */
+	u8	antenna_select:1;
+	u8	antenna_select_b:1;
+	u8	r_ant_train_en:1;
+	u8	idle_long:1;
+	u8	rxsc:2;
+	u8	sgi_en:1;
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+#endif
+};
+
+/*
+ * Regs to backup
+ */
+#define RTL8XXXU_ADDA_REGS		16
+#define RTL8XXXU_MAC_REGS		4
+#define RTL8XXXU_BB_REGS		9
+
+struct rtl8xxxu_firmware_header {
+	__le16	signature;		/*  92C0: test chip; 92C,
+					    88C0: test chip;
+					    88C1: MP A-cut;
+					    92C1: MP A-cut */
+	u8	category;		/*  AP/NIC and USB/PCI */
+	u8	function;
+
+	__le16	major_version;		/*  FW Version */
+	u8	minor_version;		/*  FW Subversion, default 0x00 */
+	u8	reserved1;
+
+	u8	month;			/*  Release time Month field */
+	u8	date;			/*  Release time Date field */
+	u8	hour;			/*  Release time Hour field */
+	u8	minute;			/*  Release time Minute field */
+
+	__le16	ramcodesize;		/*  Size of RAM code */
+	u16	reserved2;
+
+	__le32	svn_idx;		/*  SVN entry index */
+	u32	reserved3;
+
+	u32	reserved4;
+	u32	reserved5;
+
+	u8	data[0];
+};
+
+/*
+ * The 8723au has 3 channel groups: 1-3, 4-9, and 10-14
+ */
+struct rtl8723au_idx {
+#ifdef __LITTLE_ENDIAN
+	int	a:4;
+	int	b:4;
+#else
+	int	b:4;
+	int	a:4;
+#endif
+} __attribute__((packed));
+
+struct rtl8723au_efuse {
+	__le16 rtl_id;
+	u8 res0[0xe];
+	u8 cck_tx_power_index_A[3];	/* 0x10 */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
+	u8 ht40_1s_tx_power_index_B[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u8 channel_plan;		/* 0x28 */
+	u8 tssi_a;
+	u8 thermal_meter;
+	u8 rf_regulatory;
+	u8 rf_option_2;
+	u8 rf_option_3;
+	u8 rf_option_4;
+	u8 res7;
+	u8 version			/* 0x30 */;
+	u8 customer_id_major;
+	u8 customer_id_minor;
+	u8 xtal_k;
+	u8 chipset;			/* 0x34 */
+	u8 res8[0x82];
+	u8 vid;				/* 0xb7 */
+	u8 res9;
+	u8 pid;				/* 0xb9 */
+	u8 res10[0x0c];
+	u8 mac_addr[ETH_ALEN];		/* 0xc6 */
+	u8 res11[2];
+	u8 vendor_name[7];
+	u8 res12[2];
+	u8 device_name[0x29];		/* 0xd7 */
+};
+
+struct rtl8192cu_efuse {
+	__le16 rtl_id;
+	__le16 hpon;
+	u8 res0[2];
+	__le16 clk;
+	__le16 testr;
+	__le16 vid;
+	__le16 did;
+	__le16 svid;
+	__le16 smid;						/* 0x10 */
+	u8 res1[4];
+	u8 mac_addr[ETH_ALEN];					/* 0x16 */
+	u8 res2[2];
+	u8 vendor_name[7];
+	u8 res3[3];
+	u8 device_name[0x14];					/* 0x28 */
+	u8 res4[0x1e];						/* 0x3c */
+	u8 cck_tx_power_index_A[3];				/* 0x5a */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];				/* 0x60 */
+	u8 ht40_1s_tx_power_index_B[3];
+	u8 ht40_2s_tx_power_index_diff[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];	/* 0x69 */
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];		/* 0x6f */
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u8 channel_plan;					/* 0x75 */
+	u8 tssi_a;
+	u8 tssi_b;
+	u8 thermal_meter;	/* xtal_k */			/* 0x78 */
+	u8 rf_regulatory;
+	u8 rf_option_2;
+	u8 rf_option_3;
+	u8 rf_option_4;
+	u8 res5[1];						/* 0x7d */
+	u8 version;
+	u8 customer_id;
+};
+
+struct rtl8xxxu_reg8val {
+	u16 reg;
+	u8 val;
+};
+
+struct rtl8xxxu_reg32val {
+	u16 reg;
+	u32 val;
+};
+
+struct rtl8xxxu_rfregval {
+	u8 reg;
+	u32 val;
+};
+
+enum rtl8xxxu_rfpath {
+	RF_A = 0,
+	RF_B = 1,
+};
+
+struct rtl8xxxu_rfregs {
+	u16 hssiparm1;
+	u16 hssiparm2;
+	u16 lssiparm;
+	u16 hspiread;
+	u16 lssiread;
+	u16 rf_sw_ctrl;
+};
+
+#define H2C_MAX_MBOX			4
+#define H2C_EXT				BIT(7)
+#define H2C_SET_POWER_MODE		1
+#define H2C_JOIN_BSS_REPORT		2
+#define  H2C_JOIN_BSS_DISCONNECT	0
+#define  H2C_JOIN_BSS_CONNECT		1
+#define H2C_SET_RSSI			5
+#define H2C_SET_RATE_MASK		(6 | H2C_EXT)
+
+struct h2c_cmd {
+	union {
+		struct {
+			u8 cmd;
+			u8 data[5];
+		} __packed cmd;
+		struct {
+			__le32 data;
+			__le16 ext;
+		} __packed raw;
+		struct {
+			u8 cmd;
+			u8 data;
+			u8 pad[4];
+		} __packed joinbss;
+		struct {
+			u8 cmd;
+			__le16 mask_hi;
+			u8 arg;
+			__le16 mask_lo;
+		} __packed ramask;
+	};
+};
+
+struct rtl8xxxu_fileops;
+
+struct rtl8xxxu_priv {
+	struct ieee80211_hw *hw;
+	struct usb_device *udev;
+	struct rtl8xxxu_fileops *fops;
+	u8 mac_addr[ETH_ALEN];
+	char chip_name[8];
+	u8 cck_tx_power_index_A[3];	/* 0x10 */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
+	u8 ht40_1s_tx_power_index_B[3];
+	u8 ht40_2s_tx_power_index_diff[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u32 chip_cut:4;
+	u32 rom_rev:4;
+	u32 has_wifi:1;
+	u32 has_bluetooth:1;
+	u32 enable_bluetooth:1;
+	u32 has_gps:1;
+	u32 hi_pa:1;
+	u32 vendor_umc:1;
+	u32 has_polarity_ctrl:1;
+	u32 has_eeprom:1;
+	u32 boot_eeprom:1;
+	u32 ep_tx_high_queue:1;
+	u32 ep_tx_normal_queue:1;
+	u32 ep_tx_low_queue:1;
+	u32 path_a_hi_power:1;
+	u32 path_a_rf_paths:4;
+	unsigned int pipe_interrupt;
+	unsigned int pipe_in;
+	unsigned int pipe_out[TXDESC_QUEUE_MAX];
+	u8 out_ep[RTL8XXXU_OUT_ENDPOINTS];
+	u8 path_a_ig_value;
+	u8 ep_tx_count;
+	u8 rf_paths;
+	u8 rx_paths;
+	u8 tx_paths;
+	u32 rf_mode_ag[2];
+	u32 rege94;
+	u32 rege9c;
+	u32 regeb4;
+	u32 regebc;
+	int next_mbox;
+	int nr_out_eps;
+
+	struct mutex h2c_mutex;
+
+	struct usb_anchor rx_anchor;
+	struct usb_anchor tx_anchor;
+	struct usb_anchor int_anchor;
+	struct rtl8xxxu_firmware_header *fw_data;
+	size_t fw_size;
+	struct mutex usb_buf_mutex;
+	union {
+		__le32 val32;
+		__le16 val16;
+		u8 val8;
+	} usb_buf;
+	union {
+		u8 raw[EFUSE_MAP_LEN_8723A];
+		struct rtl8723au_efuse efuse8723;
+		struct rtl8192cu_efuse efuse8192;
+	} efuse_wifi;
+	u32 adda_backup[RTL8XXXU_ADDA_REGS];
+	u32 mac_backup[RTL8XXXU_MAC_REGS];
+	u32 bb_backup[RTL8XXXU_BB_REGS];
+	u32 bb_recovery_backup[RTL8XXXU_BB_REGS];
+	u32 rtlchip;
+	u8 pi_enabled:1;
+	u8 iqk_initialized:1;
+	u8 int_buf[USB_INTR_CONTENT_LENGTH];
+};
+
+struct rtl8xxxu_rx_urb {
+	struct urb urb;
+	struct ieee80211_hw *hw;
+};
+
+struct rtl8xxxu_sta_priv {
+	bool short_preamble;
+};
+
+struct rtl8xxxu_fileops {
+	int (*parse_efuse) (struct rtl8xxxu_priv *priv);
+	int (*load_firmware) (struct rtl8xxxu_priv *priv);
+	int (*power_on) (struct rtl8xxxu_priv *priv);
+	int (*writeN) (struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len);
+};
diff --git a/drivers/net/wireless/rtl8xxxu_regs.h b/drivers/net/wireless/rtl8xxxu_regs.h
new file mode 100644
index 0000000..a7aa569
--- /dev/null
+++ b/drivers/net/wireless/rtl8xxxu_regs.h
@@ -0,0 +1,980 @@
+/*
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Register definitions taken from original Realtek rtl8723au driver
+ */
+
+/* 0x0000 ~ 0x00FF	System Configuration */
+#define REG_SYS_ISO_CTRL		0x0000
+#define  SYS_ISO_MD2PP			BIT(0)
+#define  SYS_ISO_ANALOG_IPS		BIT(5)
+#define  SYS_ISO_DIOR			BIT(9)
+#define  SYS_ISO_PWC_EV25V		BIT(14)
+#define  SYS_ISO_PWC_EV12V		BIT(15)
+
+#define REG_SYS_FUNC			0x0002
+#define  SYS_FUNC_BBRSTB		BIT(0)
+#define  SYS_FUNC_BB_GLB_RSTN		BIT(1)
+#define  SYS_FUNC_USBA			BIT(2)
+#define  SYS_FUNC_UPLL			BIT(3)
+#define  SYS_FUNC_USBD			BIT(4)
+#define  SYS_FUNC_DIO_PCIE		BIT(5)
+#define  SYS_FUNC_PCIEA			BIT(6)
+#define  SYS_FUNC_PPLL			BIT(7)
+#define  SYS_FUNC_PCIED			BIT(8)
+#define  SYS_FUNC_DIOE			BIT(9)
+#define  SYS_FUNC_CPU_ENABLE		BIT(10)
+#define  SYS_FUNC_DCORE			BIT(11)
+#define  SYS_FUNC_ELDR			BIT(12)
+#define  SYS_FUNC_DIO_RF		BIT(13)
+#define  SYS_FUNC_HWPDN			BIT(14)
+#define  SYS_FUNC_MREGEN		BIT(15)
+
+#define REG_APS_FSMCO			0x0004
+#define  APS_FSMCO_PFM_ALDN		BIT(1)
+#define  APS_FSMCO_PFM_WOWL		BIT(3)
+#define  APS_FSMCO_ENABLE_POWERDOWN	BIT(4)
+#define  APS_FSMCO_MAC_ENABLE		BIT(8)
+#define  APS_FSMCO_MAC_OFF		BIT(9)
+#define  APS_FSMCO_HW_SUSPEND		BIT(11)
+#define  APS_FSMCO_PCIE			BIT(12)
+#define  APS_FSMCO_HW_POWERDOWN		BIT(15)
+#define  APS_FSMCO_WLON_RESET		BIT(16)
+
+#define REG_SYS_CLKR			0x0008
+#define  SYS_CLK_ANAD16V_ENABLE		BIT(0)
+#define  SYS_CLK_ANA8M			BIT(1)
+#define  SYS_CLK_MACSLP			BIT(4)
+#define  SYS_CLK_LOADER_ENABLE		BIT(5)
+#define  SYS_CLK_80M_SSC_DISABLE	BIT(7)
+#define  SYS_CLK_80M_SSC_ENABLE_HO	BIT(8)
+#define  SYS_CLK_PHY_SSC_RSTB		BIT(9)
+#define  SYS_CLK_SEC_CLK_ENABLE		BIT(10)
+#define  SYS_CLK_MAC_CLK_ENABLE		BIT(11)
+#define  SYS_CLK_ENABLE			BIT(12)
+#define  SYS_CLK_RING_CLK_ENABLE	BIT(13)
+
+#define REG_9346CR			0x000a
+#define  EEPROM_BOOT			BIT(4)
+#define  EEPROM_ENABLE			BIT(5)
+
+#define REG_EE_VPD			0x000c
+#define REG_AFE_MISC			0x0010
+#define REG_SPS0_CTRL			0x0011
+#define REG_SPS_OCP_CFG			0x0018
+#define REG_RSV_CTRL			0x001c
+
+#define REG_RF_CTRL			0x001f
+#define  RF_ENABLE			BIT(0)
+#define  RF_RSTB			BIT(1)
+#define  RF_SDMRSTB			BIT(2)
+
+#define REG_LDOA15_CTRL			0x0020
+#define  LDOA15_ENABLE			BIT(0)
+#define  LDOA15_STANDBY			BIT(1)
+#define  LDOA15_OBUF			BIT(2)
+#define  LDOA15_REG_VOS			BIT(3)
+#define  LDOA15_VOADJ_SHIFT		4
+
+#define REG_LDOV12D_CTRL		0x0021
+#define  LDOV12D_ENABLE			BIT(0)
+#define  LDOV12D_STANDBY		BIT(1)
+#define  LDOV12D_VADJ_SHIFT		4
+
+#define REG_LDOHCI12_CTRL		0x0022
+
+#define REG_LPLDO_CTRL			0x0023
+#define  LPLDO_HSM			BIT(2)
+#define  LPLDO_LSM_DIS			BIT(3)
+
+#define REG_AFE_XTAL_CTRL		0x0024
+#define  AFE_XTAL_ENABLE		BIT(0)
+#define  AFE_XTAL_B_SELECT		BIT(1)
+#define  AFE_XTAL_GATE_USB		BIT(8)
+#define  AFE_XTAL_GATE_AFE		BIT(11)
+#define  AFE_XTAL_RF_GATE		BIT(14)
+#define  AFE_XTAL_GATE_DIG		BIT(17)
+#define  AFE_XTAL_BT_GATE		BIT(20)
+
+#define REG_AFE_PLL_CTRL		0x0028
+#define  AFE_PLL_ENABLE			BIT(0)
+#define  AFE_PLL_320_ENABLE		BIT(1)
+#define  APE_PLL_FREF_SELECT		BIT(2)
+#define  AFE_PLL_EDGE_SELECT		BIT(3)
+#define  AFE_PLL_WDOGB			BIT(4)
+#define  AFE_PLL_LPF_ENABLE		BIT(5)
+
+#define REG_MAC_PHY_CTRL		0x002c
+
+#define REG_EFUSE_CTRL			0x0030
+#define REG_EFUSE_TEST			0x0034
+#define  EFUSE_TRPT			BIT(7)
+	/*  00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
+#define  EFUSE_CELL_SEL			(BIT(8) | BIT(9))
+#define  EFUSE_LDOE25_ENABLE		BIT(31)
+#define  EFUSE_SELECT_MASK		0x0300
+#define  EFUSE_WIFI_SELECT		0x0000
+#define  EFUSE_BT0_SELECT		0x0100
+#define  EFUSE_BT1_SELECT		0x0200
+#define  EFUSE_BT2_SELECT		0x0300
+
+#define  EFUSE_ACCESS_ENABLE		0x69	/* RTL8723 only */
+#define  EFUSE_ACCESS_DISABLE		0x00	/* RTL8723 only */
+
+#define REG_PWR_DATA			0x0038
+#define REG_CAL_TIMER			0x003c
+#define REG_ACLK_MON			0x003e
+#define REG_GPIO_MUXCFG			0x0040
+#define REG_GPIO_IO_SEL			0x0042
+#define REG_MAC_PINMUX_CFG		0x0043
+#define REG_GPIO_PIN_CTRL		0x0044
+#define REG_GPIO_INTM			0x0048
+#define REG_LEDCFG0			0x004c
+#define REG_LEDCFG1			0x004d
+#define REG_LEDCFG2			0x004e
+#define  LEDCFG2_DPDT_SELECT		BIT(7)
+#define REG_LEDCFG3			0x004f
+#define REG_LEDCFG			REG_LEDCFG2
+#define REG_FSIMR			0x0050
+#define REG_FSISR			0x0054
+#define REG_HSIMR			0x0058
+#define REG_HSISR			0x005c
+/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */
+#define REG_GPIO_PIN_CTRL_2		0x0060
+/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */
+#define REG_GPIO_IO_SEL_2		0x0062
+
+/*  RTL8723 only WIFI/BT/GPS Multi-Function control source. */
+#define REG_MULTI_FUNC_CTRL		0x0068
+
+#define  MULTI_FN_WIFI_HW_PWRDOWN_EN	BIT(0)	/* Enable GPIO[9] as WiFi HW
+						   powerdown source */
+#define  MULTI_FN_WIFI_HW_PWRDOWN_SL	BIT(1)	/* WiFi HW powerdown polarity
+						   control */
+#define  MULTI_WIFI_FUNC_EN		BIT(2)	/* WiFi function enable */
+
+#define  MULTI_WIFI_HW_ROF_EN		BIT(3)	/* Enable GPIO[9] as WiFi RF HW
+						   powerdown source */
+#define  MULTI_BT_HW_PWRDOWN_EN		BIT(16)	/* Enable GPIO[11] as BT HW
+						   powerdown source */
+#define  MULTI_BT_HW_PWRDOWN_SL		BIT(17)	/* BT HW powerdown polarity
+						   control */
+#define  MULTI_BT_FUNC_EN		BIT(18)	/* BT function enable */
+#define  MULTI_BT_HW_ROF_EN		BIT(19)	/* Enable GPIO[11] as BT/GPS
+						   RF HW powerdown source */
+#define  MULTI_GPS_HW_PWRDOWN_EN	BIT(20)	/* Enable GPIO[10] as GPS HW
+						   powerdown source */
+#define  MULTI_GPS_HW_PWRDOWN_SL	BIT(21)	/* GPS HW powerdown polarity
+						   control */
+#define  MULTI_GPS_FUNC_EN		BIT(22)	/* GPS function enable */
+
+#define REG_MCU_FW_DL			0x0080
+#define  MCU_FW_DL_ENABLE		BIT(0)
+#define  MCU_FW_DL_READY		BIT(1)
+#define  MCU_FW_DL_CSUM_REPORT		BIT(2)
+#define  MCU_MAC_INIT_READY		BIT(3)
+#define  MCU_BB_INIT_READY		BIT(4)
+#define  MCU_RF_INIT_READY		BIT(5)
+#define  MCU_WINT_INIT_READY		BIT(6)
+#define  MCU_FW_RAM_SEL			BIT(7)	/* 1: RAM, 0:ROM */
+#define  MCU_CP_RESET			BIT(23)
+
+#define REG_HMBOX_EXT_0			0x0088
+#define REG_HMBOX_EXT_1			0x008a
+#define REG_HMBOX_EXT_2			0x008c
+#define REG_HMBOX_EXT_3			0x008e
+/*  Host suspend counter on FPGA platform */
+#define REG_HOST_SUSP_CNT		0x00bc
+/*  Efuse access protection for RTL8723 */
+#define REG_EFUSE_ACCESS		0x00cf
+#define REG_BIST_SCAN			0x00d0
+#define REG_BIST_RPT			0x00d4
+#define REG_BIST_ROM_RPT		0x00d8
+#define REG_USB_SIE_INTF		0x00e0
+#define REG_PCIE_MIO_INTF		0x00e4
+#define REG_PCIE_MIO_INTD		0x00e8
+#define REG_HPON_FSM			0x00ec
+#define  HPON_FSM_BONDING_MASK		(BIT(22) | BIT(23))
+#define  HPON_FSM_BONDING_1T2R		BIT(22)
+#define REG_SYS_CFG			0x00f0
+#define  SYS_CFG_XCLK_VLD		BIT(0)
+#define  SYS_CFG_ACLK_VLD		BIT(1)
+#define  SYS_CFG_UCLK_VLD		BIT(2)
+#define  SYS_CFG_PCLK_VLD		BIT(3)
+#define  SYS_CFG_PCIRSTB		BIT(4)
+#define  SYS_CFG_V15_VLD		BIT(5)
+#define  SYS_CFG_TRP_B15V_EN		BIT(7)
+#define  SYS_CFG_SIC_IDLE		BIT(8)
+#define  SYS_CFG_BD_MAC2		BIT(9)
+#define  SYS_CFG_BD_MAC1		BIT(10)
+#define  SYS_CFG_IC_MACPHY_MODE		BIT(11)
+#define  SYS_CFG_CHIP_VER		(BIT(12) | BIT(13) | BIT(14) | BIT(15))
+#define  SYS_CFG_BT_FUNC		BIT(16)
+#define  SYS_CFG_VENDOR_ID		BIT(19)
+#define  SYS_CFG_PAD_HWPD_IDN		BIT(22)
+#define  SYS_CFG_TRP_VAUX_EN		BIT(23)
+#define  SYS_CFG_TRP_BT_EN		BIT(24)
+#define  SYS_CFG_BD_PKG_SEL		BIT(25)
+#define  SYS_CFG_BD_HCI_SEL		BIT(26)
+#define  SYS_CFG_TYPE_ID		BIT(27)
+#define  SYS_CFG_RTL_ID			BIT(23) /*  TestChip ID,
+						    1:Test(RLE); 0:MP(RL) */
+#define  SYS_CFG_SPS_SEL		BIT(24) /*  1:LDO regulator mode;
+						    0:Switching regulator mode*/
+#define  SYS_CFG_CHIP_VERSION_MASK	0xf000	/* Bit 12 - 15 */
+#define  SYS_CFG_CHIP_VERSION_SHIFT	12
+
+#define REG_GPIO_OUTSTS			0x00f4	/*  For RTL8723 only. */
+#define  GPIO_EFS_HCI_SEL		(BIT(0) | BIT(1))
+#define  GPIO_PAD_HCI_SEL		(BIT(2) | BIT(3))
+#define  GPIO_HCI_SEL			(BIT(4) | BIT(5))
+#define  GPIO_PKG_SEL_HCI		BIT(6)
+#define  GPIO_FEN_GPS			BIT(7)
+#define  GPIO_FEN_BT			BIT(8)
+#define  GPIO_FEN_WL			BIT(9)
+#define  GPIO_FEN_PCI			BIT(10)
+#define  GPIO_FEN_USB			BIT(11)
+#define  GPIO_BTRF_HWPDN_N		BIT(12)
+#define  GPIO_WLRF_HWPDN_N		BIT(13)
+#define  GPIO_PDN_BT_N			BIT(14)
+#define  GPIO_PDN_GPS_N			BIT(15)
+#define  GPIO_BT_CTL_HWPDN		BIT(16)
+#define  GPIO_GPS_CTL_HWPDN		BIT(17)
+#define  GPIO_PPHY_SUSB			BIT(20)
+#define  GPIO_UPHY_SUSB			BIT(21)
+#define  GPIO_PCI_SUSEN			BIT(22)
+#define  GPIO_USB_SUSEN			BIT(23)
+#define  GPIO_RF_RL_ID			(BIT(31) | BIT(30) | BIT(29) | BIT(28))
+
+/* 0x0100 ~ 0x01FF	MACTOP General Configuration */
+#define REG_CR				0x0100
+#define  CR_HCI_TXDMA_ENABLE		BIT(0)
+#define  CR_HCI_RXDMA_ENABLE		BIT(1)
+#define  CR_TXDMA_ENABLE		BIT(2)
+#define  CR_RXDMA_ENABLE		BIT(3)
+#define  CR_PROTOCOL_ENABLE		BIT(4)
+#define  CR_SCHEDULE_ENABLE		BIT(5)
+#define  CR_MAC_TX_ENABLE		BIT(6)
+#define  CR_MAC_RX_ENABLE		BIT(7)
+#define  CR_SW_BEACON_ENABLE		BIT(8)
+#define  CR_SECURITY_ENABLE		BIT(9)
+#define  CR_CALTIMER_ENABLE		BIT(10)
+
+/* Media Status Register */
+#define REG_MSR				0x0102
+#define  MSR_LINKTYPE_MASK		0x3
+#define  MSR_LINKTYPE_NONE		0x0
+#define  MSR_LINKTYPE_ADHOC		0x1
+#define  MSR_LINKTYPE_STATION		0x2
+#define  MSR_LINKTYPE_AP		0x3
+
+#define REG_PBP				0x0104
+#define  PBP_PAGE_SIZE_RX_SHIFT		0
+#define  PBP_PAGE_SIZE_TX_SHIFT		4
+#define  PBP_PAGE_SIZE_64		0x0
+#define  PBP_PAGE_SIZE_128		0x1
+#define  PBP_PAGE_SIZE_256		0x2
+#define  PBP_PAGE_SIZE_512		0x3
+#define  PBP_PAGE_SIZE_1024		0x4
+
+#define REG_TRXDMA_CTRL			0x010c
+#define  TRXDMA_CTRL_VOQ_SHIFT		4
+#define  TRXDMA_CTRL_VIQ_SHIFT		6
+#define  TRXDMA_CTRL_BEQ_SHIFT		8
+#define  TRXDMA_CTRL_BKQ_SHIFT		10
+#define  TRXDMA_CTRL_MGQ_SHIFT		12
+#define  TRXDMA_CTRL_HIQ_SHIFT		14
+#define  TRXDMA_QUEUE_LOW		1
+#define  TRXDMA_QUEUE_NORMAL		2
+#define  TRXDMA_QUEUE_HIGH		3
+
+#define REG_TRXFF_BNDY			0x0114
+#define REG_TRXFF_STATUS		0x0118
+#define REG_RXFF_PTR			0x011c
+#define REG_HIMR			0x0120
+#define REG_HISR			0x0124
+#define REG_HIMRE			0x0128
+#define REG_HISRE			0x012c
+#define REG_CPWM			0x012f
+#define REG_FWIMR			0x0130
+#define REG_FWISR			0x0134
+#define REG_PKTBUF_DBG_CTRL		0x0140
+#define REG_PKTBUF_DBG_DATA_L		0x0144
+#define REG_PKTBUF_DBG_DATA_H		0x0148
+
+#define REG_TC0_CTRL			0x0150
+#define REG_TC1_CTRL			0x0154
+#define REG_TC2_CTRL			0x0158
+#define REG_TC3_CTRL			0x015c
+#define REG_TC4_CTRL			0x0160
+#define REG_TCUNIT_BASE			0x0164
+#define REG_MBIST_START			0x0174
+#define REG_MBIST_DONE			0x0178
+#define REG_MBIST_FAIL			0x017c
+#define REG_C2HEVT_MSG_NORMAL		0x01a0
+#define REG_C2HEVT_CLEAR		0x01af
+#define REG_C2HEVT_MSG_TEST		0x01b8
+#define REG_MCUTST_1			0x01c0
+#define REG_FMTHR			0x01c8
+#define REG_HMTFR			0x01cc
+#define REG_HMBOX_0			0x01d0
+#define REG_HMBOX_1			0x01d4
+#define REG_HMBOX_2			0x01d8
+#define REG_HMBOX_3			0x01dc
+
+#define REG_LLT_INIT			0x01e0
+#define  LLT_OP_INACTIVE		0x0
+#define  LLT_OP_WRITE			(0x1 << 30)
+#define  LLT_OP_READ			(0x2 << 30)
+#define  LLT_OP_MASK			(0x3 << 30)
+
+#define REG_BB_ACCEESS_CTRL		0x01e8
+#define REG_BB_ACCESS_DATA		0x01ec
+
+/* 0x0200 ~ 0x027F	TXDMA Configuration */
+#define REG_RQPN			0x0200
+#define  RQPN_HI_PQ_SHIFT		0
+#define  RQPN_LO_PQ_SHIFT		8
+#define  RQPN_NORM_PQ_SHIFT		16
+#define  RQPN_LOAD			BIT(31)
+
+#define REG_FIFOPAGE			0x0204
+#define REG_TDECTRL			0x0208
+#define REG_TXDMA_OFFSET_CHK		0x020c
+#define REG_TXDMA_STATUS		0x0210
+#define REG_RQPN_NPQ			0x0214
+
+/* 0x0280 ~ 0x02FF	RXDMA Configuration */
+#define REG_RXDMA_AGG_PG_TH		0x0280
+#define REG_RXPKT_NUM			0x0284
+#define REG_RXDMA_STATUS		0x0288
+
+#define REG_RF_BB_CMD_ADDR		0x02c0
+#define REG_RF_BB_CMD_DATA		0x02c4
+
+/*  spec version 11 */
+/* 0x0400 ~ 0x047F	Protocol Configuration */
+#define REG_VOQ_INFORMATION		0x0400
+#define REG_VIQ_INFORMATION		0x0404
+#define REG_BEQ_INFORMATION		0x0408
+#define REG_BKQ_INFORMATION		0x040c
+#define REG_MGQ_INFORMATION		0x0410
+#define REG_HGQ_INFORMATION		0x0414
+#define REG_BCNQ_INFORMATION		0x0418
+
+#define REG_CPU_MGQ_INFORMATION		0x041c
+#define REG_FWHW_TXQ_CTRL		0x0420
+#define  FWHW_TXQ_CTRL_AMPDU_RETRY	BIT(7)
+#define  FWHW_TXQ_CTRL_XMIT_MGMT_ACK	BIT(12)
+
+#define REG_HWSEQ_CTRL			0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
+#define REG_TXPKTBUF_MGQ_BDNY		0x0425
+#define REG_LIFETIME_EN			0x0426
+#define REG_MULTI_BCNQ_OFFSET		0x0427
+
+#define REG_SPEC_SIFS			0x0428
+#define  SPEC_SIFS_CCK_MASK		0x00ff
+#define  SPEC_SIFS_CCK_SHIFT		0
+#define  SPEC_SIFS_OFDM_MASK		0xff00
+#define  SPEC_SIFS_OFDM_SHIFT		8
+
+#define REG_RETRY_LIMIT			0x042a
+#define  RETRY_LIMIT_LONG_SHIFT		0
+#define  RETRY_LIMIT_LONG_MASK		0x003f
+#define  RETRY_LIMIT_SHORT_SHIFT	8
+#define  RETRY_LIMIT_SHORT_MASK		0x3f00
+
+#define REG_DARFRC			0x0430
+#define REG_RARFRC			0x0438
+#define REG_RESPONSE_RATE_SET		0x0440
+#define  RESPONSE_RATE_BITMAP_ALL	0xfffff
+#define  RESPONSE_RATE_RRSR_CCK_ONLY_1M	0xffff1
+#define  RSR_1M				BIT(0)
+#define  RSR_2M				BIT(1)
+#define  RSR_5_5M			BIT(2)
+#define  RSR_11M			BIT(3)
+#define  RSR_6M				BIT(4)
+#define  RSR_9M				BIT(5)
+#define  RSR_12M			BIT(6)
+#define  RSR_18M			BIT(7)
+#define  RSR_24M			BIT(8)
+#define  RSR_36M			BIT(9)
+#define  RSR_48M			BIT(10)
+#define  RSR_54M			BIT(11)
+#define  RSR_MCS0			BIT(12)
+#define  RSR_MCS1			BIT(13)
+#define  RSR_MCS2			BIT(14)
+#define  RSR_MCS3			BIT(15)
+#define  RSR_MCS4			BIT(16)
+#define  RSR_MCS5			BIT(17)
+#define  RSR_MCS6			BIT(18)
+#define  RSR_MCS7			BIT(19)
+#define  RSR_RSC_LOWER_SUB_CHANNEL	BIT(21)	/* 0x200000 */
+#define  RSR_RSC_UPPER_SUB_CHANNEL	BIT(22)	/* 0x400000 */
+#define  RSR_RSC_BANDWIDTH_40M		(RSR_RSC_UPPER_SUB_CHANNEL | \
+					 RSR_RSC_LOWER_SUB_CHANNEL)
+#define  RSR_ACK_SHORT_PREAMBLE		BIT(23)
+
+#define REG_ARFR0			0x0444
+#define REG_ARFR1			0x0448
+#define REG_ARFR2			0x044c
+#define REG_ARFR3			0x0450
+#define REG_AGGLEN_LMT			0x0458
+#define REG_AMPDU_MIN_SPACE		0x045c
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD	0x045d
+#define REG_FAST_EDCA_CTRL		0x0460
+#define REG_RD_RESP_PKT_TH		0x0463
+#define REG_INIRTS_RATE_SEL		0x0480
+#define REG_INIDATA_RATE_SEL		0x0484
+
+#define REG_POWER_STATUS		0x04a4
+#define REG_POWER_STAGE1		0x04b4
+#define REG_POWER_STAGE2		0x04b8
+#define REG_PKT_VO_VI_LIFE_TIME		0x04c0
+#define REG_PKT_BE_BK_LIFE_TIME		0x04c2
+#define REG_STBC_SETTING		0x04c4
+#define REG_PROT_MODE_CTRL		0x04c8
+#define REG_MAX_AGGR_NUM		0x04ca
+#define REG_RTS_MAX_AGGR_NUM		0x04cb
+#define REG_BAR_MODE_CTRL		0x04cc
+#define REG_RA_TRY_RATE_AGG_LMT		0x04cf
+#define REG_NQOS_SEQ			0x04dc
+#define REG_QOS_SEQ			0x04de
+#define REG_NEED_CPU_HANDLE		0x04e0
+#define REG_PKT_LOSE_RPT		0x04e1
+#define REG_PTCL_ERR_STATUS		0x04e2
+#define REG_DUMMY			0x04fc
+
+/* 0x0500 ~ 0x05FF	EDCA Configuration */
+#define REG_EDCA_VO_PARAM		0x0500
+#define REG_EDCA_VI_PARAM		0x0504
+#define REG_EDCA_BE_PARAM		0x0508
+#define REG_EDCA_BK_PARAM		0x050c
+#define  EDCA_PARAM_ECW_MIN_SHIFT	8
+#define  EDCA_PARAM_ECW_MAX_SHIFT	12
+#define  EDCA_PARAM_TXOP_SHIFT		16
+#define REG_BEACON_TCFG			0x0510
+#define REG_PIFS			0x0512
+#define REG_RDG_PIFS			0x0513
+#define REG_SIFS_CCK			0x0514
+#define REG_SIFS_OFDM			0x0516
+#define REG_TSFTR_SYN_OFFSET		0x0518
+#define REG_AGGR_BREAK_TIME		0x051a
+#define REG_SLOT			0x051b
+#define REG_TX_PTCL_CTRL		0x0520
+#define REG_TXPAUSE			0x0522
+#define REG_DIS_TXREQ_CLR		0x0523
+#define REG_RD_CTRL			0x0524
+#define REG_TBTT_PROHIBIT		0x0540
+#define REG_RD_NAV_NXT			0x0544
+#define REG_NAV_PROT_LEN		0x0546
+
+#define REG_BEACON_CTRL			0x0550
+#define REG_BEACON_CTRL_1		0x0551
+#define  BEACON_ATIM			BIT(0)
+#define  BEACON_CTRL_MBSSID		BIT(1)
+#define  BEACON_CTRL_TX_BEACON_RPT	BIT(2)
+#define  BEACON_FUNCTION_ENABLE		BIT(3)
+#define  BEACON_DISABLE_TSF_UPDATE	BIT(4)
+
+#define REG_MBID_NUM			0x0552
+#define REG_DUAL_TSF_RST		0x0553
+#define  DUAL_TSF_RESET_TSF0		BIT(0)
+#define  DUAL_TSF_RESET_TSF1		BIT(1)
+#define  DUAL_TSF_RESET_P2P		BIT(4)
+#define  DUAL_TSF_TX_OK			BIT(5)
+
+/*  The same as REG_MBSSID_BCN_SPACE */
+#define REG_BCN_INTERVAL		0x0554
+#define REG_MBSSID_BCN_SPACE		0x0554
+
+#define REG_DRIVER_EARLY_INT		0x0558
+#define  DRIVER_EARLY_INT_TIME		5
+
+#define REG_BEACON_DMA_TIME		0x0559
+#define  BEACON_DMA_ATIME_INT_TIME	2
+
+#define REG_ATIMWND			0x055a
+#define REG_BCN_MAX_ERR			0x055d
+#define REG_RXTSF_OFFSET_CCK		0x055e
+#define REG_RXTSF_OFFSET_OFDM		0x055f
+#define REG_TSFTR			0x0560
+#define REG_TSFTR1			0x0568
+#define REG_INIT_TSFTR			0x0564
+#define REG_ATIMWND_1			0x0570
+#define REG_PSTIMER			0x0580
+#define REG_TIMER0			0x0584
+#define REG_TIMER1			0x0588
+#define REG_ACM_HW_CTRL			0x05c0
+#define  ACM_HW_CTRL_BK			BIT(0)
+#define  ACM_HW_CTRL_BE			BIT(1)
+#define  ACM_HW_CTRL_VI			BIT(2)
+#define  ACM_HW_CTRL_VO			BIT(3)
+#define REG_ACM_RST_CTRL		0x05c1
+#define REG_ACMAVG			0x05c2
+#define REG_VO_ADMTIME			0x05c4
+#define REG_VI_ADMTIME			0x05c6
+#define REG_BE_ADMTIME			0x05c8
+#define REG_EDCA_RANDOM_GEN		0x05cc
+#define REG_SCH_TXCMD			0x05d0
+
+/* define REG_FW_TSF_SYNC_CNT		0x04a0 */
+#define REG_FW_RESET_TSF_CNT_1		0x05fc
+#define REG_FW_RESET_TSF_CNT_0		0x05fd
+#define REG_FW_BCN_DIS_CNT		0x05fe
+
+/* 0x0600 ~ 0x07FF  WMAC Configuration */
+#define REG_APSD_CTRL			0x0600
+#define  APSD_CTRL_OFF			BIT(6)
+#define  APSD_CTRL_OFF_STATUS		BIT(7)
+#define REG_BW_OPMODE			0x0603
+#define  BW_OPMODE_20MHZ		BIT(2)
+#define  BW_OPMODE_5G			BIT(1)
+#define  BW_OPMODE_11J			BIT(0)
+
+#define REG_TCR				0x0604
+
+/* Receive Configuration Register */
+#define REG_RCR				0x0608
+#define  RCR_ACCEPT_AP			BIT(0)  /* Accept all unicast packet */
+#define  RCR_ACCEPT_PHYS_MATCH		BIT(1)  /* Accept phys match packet */
+#define  RCR_ACCEPT_MCAST		BIT(2)
+#define  RCR_ACCEPT_BCAST		BIT(3)
+#define  RCR_ACCEPT_ADDR3		BIT(4)  /* Accept address 3 match
+						 packet */
+#define  RCR_ACCEPT_PM			BIT(5)  /* Accept power management
+						 packet */
+#define  RCR_CHECK_BSSID_MATCH		BIT(6)  /* Accept BSSID match packet */
+#define  RCR_CHECK_BSSID_BEACON		BIT(7)  /* Accept BSSID match packet
+						 (Rx beacon, probe rsp) */
+#define  RCR_ACCEPT_CRC32		BIT(8)  /* Accept CRC32 error packet */
+#define  RCR_ACCEPT_ICV			BIT(9)  /* Accept ICV error packet */
+#define  RCR_ACCEPT_DATA_FRAME		BIT(11)
+#define  RCR_ACCEPT_CTRL_FRAME		BIT(12)
+#define  RCR_ACCEPT_MGMT_FRAME		BIT(13)
+#define  RCR_HTC_LOC_CTRL		BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */
+#define  RCR_MFBEN			BIT(22)
+#define  RCR_LSIGEN			BIT(23)
+#define  RCR_MULTI_BSSID_ENABLE		BIT(24) /* Enable Multiple BssId */
+#define  RCR_ACCEPT_BA_SSN		BIT(27) /* Accept BA SSN */
+#define  RCR_APPEND_PHYSTAT		BIT(28)
+#define  RCR_APPEND_ICV			BIT(29)
+#define  RCR_APPEND_MIC			BIT(30)
+#define  RCR_APPEND_FCS			BIT(31) /* WMAC append FCS after */
+
+#define REG_RX_PKT_LIMIT		0x060c
+#define REG_RX_DLK_TIME			0x060d
+#define REG_RX_DRVINFO_SZ		0x060f
+
+#define REG_MACID			0x0610
+#define REG_BSSID			0x0618
+#define REG_MAR				0x0620
+#define REG_MBIDCAMCFG			0x0628
+
+#define REG_USTIME_EDCA			0x0638
+#define REG_MAC_SPEC_SIFS		0x063a
+
+/*  20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
+	/*  [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
+#define REG_R2T_SIFS			0x063c
+	/*  [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
+#define REG_T2T_SIFS			0x063e
+#define REG_ACKTO			0x0640
+#define REG_CTS2TO			0x0641
+#define REG_EIFS			0x0642
+
+/* WMA, BA, CCX */
+#define REG_NAV_CTRL			0x0650
+/* In units of 128us */
+#define REG_NAV_UPPER			0x0652
+#define  NAV_UPPER_UNIT			128
+
+#define REG_BACAMCMD			0x0654
+#define REG_BACAMCONTENT		0x0658
+#define REG_LBDLY			0x0660
+#define REG_FWDLY			0x0661
+#define REG_RXERR_RPT			0x0664
+#define REG_WMAC_TRXPTCL_CTL		0x0668
+
+/*  Security */
+#define REG_CAM_CMD			0x0670
+#define  CAM_CMD_POLLING		BIT(31)
+#define  CAM_CMD_WRITE			BIT(16)
+#define  CAM_CMD_KEY_SHIFT		3
+#define REG_CAM_WRITE			0x0674
+#define  CAM_WRITE_VALID		BIT(15)
+#define REG_CAM_READ			0x0678
+#define REG_CAM_DEBUG			0x067c
+#define REG_SECURITY_CFG		0x0680
+#define  SEC_CFG_TX_USE_DEFKEY		BIT(0)
+#define  SEC_CFG_RX_USE_DEFKEY		BIT(1)
+#define  SEC_CFG_TX_SEC_ENABLE		BIT(2)
+#define  SEC_CFG_RX_SEC_ENABLE		BIT(3)
+#define  SEC_CFG_SKBYA2			BIT(4)
+#define  SEC_CFG_NO_SKMC		BIT(5)
+#define  SEC_CFG_TXBC_USE_DEFKEY	BIT(6)
+#define  SEC_CFG_RXBC_USE_DEFKEY	BIT(7)
+
+/*  Power */
+#define REG_WOW_CTRL			0x0690
+#define REG_PSSTATUS			0x0691
+#define REG_PS_RX_INFO			0x0692
+#define REG_LPNAV_CTRL			0x0694
+#define REG_WKFMCAM_CMD			0x0698
+#define REG_WKFMCAM_RWD			0x069c
+#define REG_RXFLTMAP0			0x06a0
+#define REG_RXFLTMAP1			0x06a2
+#define REG_RXFLTMAP2			0x06a4
+#define REG_BCN_PSR_RPT			0x06a8
+#define REG_CALB32K_CTRL		0x06ac
+#define REG_PKT_MON_CTRL		0x06b4
+#define REG_BT_COEX_TABLE		0x06c0
+#define REG_WMAC_RESP_TXINFO		0x06d8
+
+#define REG_MACID1			0x0700
+#define REG_BSSID1			0x0708
+
+#define REG_FPGA0_RF_MODE		0x0800
+#define  FPGA_RF_MODE			BIT(0)
+#define  FPGA_RF_MODE_JAPAN		BIT(1)
+#define  FPGA_RF_MODE_CCK		BIT(24)
+#define  FPGA_RF_MODE_OFDM		BIT(25)
+
+#define REG_FPGA0_TX_INFO		0x0804
+#define REG_FPGA0_PSD_FUNC		0x0808
+#define REG_FPGA0_TX_GAIN		0x080c
+#define REG_FPGA0_RF_TIMING1		0x0810
+#define REG_FPGA0_RF_TIMING2		0x0814
+#define REG_FPGA0_POWER_SAVE		0x0818
+#define  FPGA0_PS_LOWER_CHANNEL		BIT(26)
+#define  FPGA0_PS_UPPER_CHANNEL		BIT(27)
+
+#define REG_FPGA0_XA_HSSI_PARM1		0x0820	/* RF 3 wire register */
+#define  FPGA0_HSSI_PARM1_PI		BIT(8)
+#define REG_FPGA0_XA_HSSI_PARM2		0x0824
+#define REG_FPGA0_XB_HSSI_PARM1		0x0828
+#define REG_FPGA0_XB_HSSI_PARM2		0x082c
+#define  FPGA0_HSSI_3WIRE_DATA_LEN	0x800
+#define  FPGA0_HSSI_3WIRE_ADDR_LEN	0x400
+#define  FPGA0_HSSI_PARM2_ADDR_SHIFT	23
+#define  FPGA0_HSSI_PARM2_ADDR_MASK	0x7f800000	/* 0xff << 23 */
+#define  FPGA0_HSSI_PARM2_CCK_HIGH_PWR	BIT(9)
+#define  FPGA0_HSSI_PARM2_EDGE_READ	BIT(31)
+
+#define REG_TX_AGC_B_RATE18_06		0x0830
+#define REG_TX_AGC_B_RATE54_24		0x0834
+#define REG_TX_AGC_B_CCK1_55_MCS32	0x0838
+#define REG_TX_AGC_B_MCS03_MCS00	0x083c
+
+#define REG_FPGA0_XA_LSSI_PARM		0x0840
+#define REG_FPGA0_XB_LSSI_PARM		0x0844
+#define  FPGA0_LSSI_PARM_ADDR_SHIFT	20
+#define  FPGA0_LSSI_PARM_ADDR_MASK	0x0ff00000
+#define  FPGA0_LSSI_PARM_DATA_MASK	0x000fffff
+
+#define REG_TX_AGC_B_MCS07_MCS04	0x0848
+#define REG_TX_AGC_B_MCS11_MCS08	0x084c
+
+#define REG_FPGA0_XCD_SWITCH_CTRL	0x085c
+
+#define REG_FPGA0_XA_RF_INT_OE		0x0860	/* RF Channel switch */
+#define REG_FPGA0_XB_RF_INT_OE		0x0864
+#define  FPGA0_INT_OE_ANTENNA_AB_OPEN	0x000
+#define  FPGA0_INT_OE_ANTENNA_A		0x100
+#define  FPGA0_INT_OE_ANTENNA_B		0x200
+#define  FPGA0_INT_OE_ANTENNA_MASK	0x300
+
+#define REG_TX_AGC_B_MCS15_MCS12	0x0868
+#define REG_TX_AGC_B_CCK11_A_CCK2_11	0x086c
+
+#define REG_FPGA0_XAB_RF_SW_CTRL	0x0870
+#define REG_FPGA0_XA_RF_SW_CTRL		0x0870	/* 16 bit */
+#define REG_FPGA0_XB_RF_SW_CTRL		0x0872	/* 16 bit */
+#define REG_FPGA0_XCD_RF_SW_CTRL	0x0874
+#define REG_FPGA0_XC_RF_SW_CTRL		0x0874	/* 16 bit */
+#define REG_FPGA0_XD_RF_SW_CTRL		0x0876	/* 16 bit */
+#define  FPGA0_RF_3WIRE_DATA		BIT(0)
+#define  FPGA0_RF_3WIRE_CLOC		BIT(1)
+#define  FPGA0_RF_3WIRE_LOAD		BIT(2)
+#define  FPGA0_RF_3WIRE_RW		BIT(3)
+#define  FPGA0_RF_3WIRE_MASK		0xf
+#define  FPGA0_RF_RFENV			BIT(4)
+#define  FPGA0_RF_TRSW			BIT(5)	/* Useless now */
+#define  FPGA0_RF_TRSWB			BIT(6)
+#define  FPGA0_RF_ANTSW			BIT(8)
+#define  FPGA0_RF_ANTSWB		BIT(9)
+#define  FPGA0_RF_PAPE			BIT(10)
+#define  FPGA0_RF_PAPE5G		BIT(11)
+#define  FPGA0_RF_BD_CTRL_SHIFT		16
+
+#define REG_FPGA0_XAB_RF_PARM		0x0878	/* Antenna select path in ODM */
+#define REG_FPGA0_XA_RF_PARM		0x0878	/* 16 bit */
+#define REG_FPGA0_XB_RF_PARM		0x087a	/* 16 bit */
+#define REG_FPGA0_XCD_RF_PARM		0x087c
+#define REG_FPGA0_XC_RF_PARM		0x087c	/* 16 bit */
+#define REG_FPGA0_XD_RF_PARM		0x087e	/* 16 bit */
+#define  FPGA0_RF_PARM_RFA_ENABLE	BIT(1)
+#define  FPGA0_RF_PARM_RFB_ENABLE	BIT(17)
+#define  FPGA0_RF_PARM_CLK_GATE		BIT(31)
+
+#define REG_FPGA0_ANALOG1		0x0880
+#define REG_FPGA0_ANALOG2		0x0884
+#define  FPGA0_ANALOG2_20MHZ		BIT(10)
+#define REG_FPGA0_ANALOG3		0x0888
+#define REG_FPGA0_ANALOG4		0x088c
+
+#define REG_FPGA0_XA_LSSI_READBACK	0x08a0	/* Tranceiver LSSI Readback */
+#define REG_FPGA0_XB_LSSI_READBACK	0x08a4
+#define REG_HSPI_XA_READBACK		0x08b8	/* Transceiver A HSPI read */
+#define REG_HSPI_XB_READBACK		0x08bc	/* Transceiver B HSPI read */
+
+#define REG_FPGA1_RF_MODE		0x0900
+
+#define REG_FPGA1_TX_INFO		0x090c
+
+#define REG_CCK0_SYSTEM			0x0a00
+#define  CCK0_SIDEBAND			BIT(4)
+
+#define REG_CCK0_AFE_SETTING		0x0a04
+
+#define REG_CONFIG_ANT_A		0x0b68
+#define REG_CONFIG_ANT_B		0x0b6c
+
+#define REG_OFDM0_TRX_PATH_ENABLE	0x0c04
+#define OFDM_RF_PATH_RX_MASK		0x0f
+#define OFDM_RF_PATH_RX_A		BIT(0)
+#define OFDM_RF_PATH_RX_B		BIT(1)
+#define OFDM_RF_PATH_RX_C		BIT(2)
+#define OFDM_RF_PATH_RX_D		BIT(3)
+#define OFDM_RF_PATH_TX_MASK		0xf0
+#define OFDM_RF_PATH_TX_A		BIT(4)
+#define OFDM_RF_PATH_TX_B		BIT(5)
+#define OFDM_RF_PATH_TX_C		BIT(6)
+#define OFDM_RF_PATH_TX_D		BIT(7)
+
+#define REG_OFDM0_TR_MUX_PAR		0x0c08
+
+#define REG_OFDM0_XA_RX_IQ_IMBALANCE	0x0c14
+#define REG_OFDM0_XB_RX_IQ_IMBALANCE	0x0c1c
+
+#define REG_OFDM0_ENERGY_CCA_THRES	0x0c4c
+
+#define REG_OFDM0_XA_AGC_CORE1		0x0c50
+#define REG_OFDM0_XA_AGC_CORE2		0x0c54
+#define REG_OFDM0_XB_AGC_CORE1		0x0c58
+#define REG_OFDM0_XB_AGC_CORE2		0x0c5c
+#define REG_OFDM0_XC_AGC_CORE1		0x0c60
+#define REG_OFDM0_XC_AGC_CORE2		0x0c64
+#define REG_OFDM0_XD_AGC_CORE1		0x0c68
+#define REG_OFDM0_XD_AGC_CORE2		0x0c6c
+#define  OFDM0_X_AGC_CORE1_IGI_MASK	0x0000007F
+
+#define REG_OFDM0_AGC_PARM1		0x0c70
+
+#define REG_OFDM0_AGCR_SSI_TABLE	0x0c78
+
+#define REG_OFDM0_XA_TX_IQ_IMBALANCE	0x0c80
+#define REG_OFDM0_XB_TX_IQ_IMBALANCE	0x0c88
+#define REG_OFDM0_XC_TX_IQ_IMBALANCE	0x0c90
+#define REG_OFDM0_XD_TX_IQ_IMBALANCE	0x0c98
+
+#define REG_OFDM0_XC_TX_AFE		0x0c94
+#define REG_OFDM0_XD_TX_AFE		0x0c9c
+
+#define REG_OFDM0_RX_IQ_EXT_ANTA	0x0ca0
+
+#define REG_OFDM1_LSTF			0x0d00
+#define  OFDM_LSTF_PRIME_CH_LOW		BIT(10)
+#define  OFDM_LSTF_PRIME_CH_HIGH	BIT(11)
+#define  OFDM_LSTF_PRIME_CH_MASK	(OFDM_LSTF_PRIME_CH_LOW | \
+					 OFDM_LSTF_PRIME_CH_HIGH)
+#define  OFDM_LSTF_CONTINUE_TX		BIT(28)
+#define  OFDM_LSTF_SINGLE_CARRIER	BIT(29)
+#define  OFDM_LSTF_SINGLE_TONE		BIT(30)
+#define  OFDM_LSTF_MASK			0x70000000
+
+#define REG_OFDM1_TRX_PATH_ENABLE	0x0d04
+
+#define REG_TX_AGC_A_RATE18_06		0x0e00
+#define REG_TX_AGC_A_RATE54_24		0x0e04
+#define REG_TX_AGC_A_CCK1_MCS32		0x0e08
+#define REG_TX_AGC_A_MCS03_MCS00	0x0e10
+#define REG_TX_AGC_A_MCS07_MCS04	0x0e14
+#define REG_TX_AGC_A_MCS11_MCS08	0x0e18
+#define REG_TX_AGC_A_MCS15_MCS12	0x0e1c
+
+#define REG_FPGA0_IQK			0x0e28
+
+#define REG_TX_IQK_TONE_A		0x0e30
+#define REG_RX_IQK_TONE_A		0x0e34
+#define REG_TX_IQK_PI_A			0x0e38
+#define REG_RX_IQK_PI_A			0x0e3c
+
+#define REG_TX_IQK			0x0e40
+#define REG_RX_IQK			0x0e44
+#define REG_IQK_AGC_PTS			0x0e48
+#define REG_IQK_AGC_RSP			0x0e4c
+#define REG_TX_IQK_TONE_B		0x0e50
+#define REG_RX_IQK_TONE_B		0x0e54
+#define REG_TX_IQK_PI_B			0x0e58
+#define REG_RX_IQK_PI_B			0x0e5c
+#define REG_IQK_AGC_CONT		0x0e60
+
+#define REG_BLUETOOTH			0x0e6c
+#define REG_RX_WAIT_CCA			0x0e70
+#define REG_TX_CCK_RFON			0x0e74
+#define REG_TX_CCK_BBON			0x0e78
+#define REG_TX_OFDM_RFON		0x0e7c
+#define REG_TX_OFDM_BBON		0x0e80
+#define REG_TX_TO_RX			0x0e84
+#define REG_TX_TO_TX			0x0e88
+#define REG_RX_CCK			0x0e8c
+
+#define REG_TX_POWER_BEFORE_IQK_A	0x0e94
+#define REG_TX_POWER_AFTER_IQK_A	0x0e9c
+
+#define REG_RX_POWER_BEFORE_IQK_A	0x0ea0
+#define REG_RX_POWER_BEFORE_IQK_A_2	0x0ea4
+#define REG_RX_POWER_AFTER_IQK_A	0x0ea8
+#define REG_RX_POWER_AFTER_IQK_A_2	0x0eac
+
+#define REG_TX_POWER_BEFORE_IQK_B	0x0eb4
+#define REG_TX_POWER_AFTER_IQK_B	0x0ebc
+
+#define REG_RX_POWER_BEFORE_IQK_B	0x0ec0
+#define REG_RX_POWER_BEFORE_IQK_B_2	0x0ec4
+#define REG_RX_POWER_AFTER_IQK_B	0x0ec8
+#define REG_RX_POWER_AFTER_IQK_B_2	0x0ecc
+
+#define REG_RX_OFDM			0x0ed0
+#define REG_RX_WAIT_RIFS		0x0ed4
+#define REG_RX_TO_RX			0x0ed8
+#define REG_STANDBY			0x0edc
+#define REG_SLEEP			0x0ee0
+#define REG_PMPD_ANAEN			0x0eec
+
+#define REG_FW_START_ADDRESS		0x1000
+
+#define REG_USB_INFO			0xfe17
+#define REG_USB_HIMR			0xfe38
+#define  USB_HIMR_TIMEOUT2		BIT(31)
+#define  USB_HIMR_TIMEOUT1		BIT(30)
+#define  USB_HIMR_PSTIMEOUT		BIT(29)
+#define  USB_HIMR_GTINT4		BIT(28)
+#define  USB_HIMR_GTINT3		BIT(27)
+#define  USB_HIMR_TXBCNERR		BIT(26)
+#define  USB_HIMR_TXBCNOK		BIT(25)
+#define  USB_HIMR_TSF_BIT32_TOGGLE	BIT(24)
+#define  USB_HIMR_BCNDMAINT3		BIT(23)
+#define  USB_HIMR_BCNDMAINT2		BIT(22)
+#define  USB_HIMR_BCNDMAINT1		BIT(21)
+#define  USB_HIMR_BCNDMAINT0		BIT(20)
+#define  USB_HIMR_BCNDOK3		BIT(19)
+#define  USB_HIMR_BCNDOK2		BIT(18)
+#define  USB_HIMR_BCNDOK1		BIT(17)
+#define  USB_HIMR_BCNDOK0		BIT(16)
+#define  USB_HIMR_HSISR_IND		BIT(15)
+#define  USB_HIMR_BCNDMAINT_E		BIT(14)
+/* RSVD	BIT(13) */
+#define  USB_HIMR_CTW_END		BIT(12)
+/* RSVD	BIT(11) */
+#define  USB_HIMR_C2HCMD		BIT(10)
+#define  USB_HIMR_CPWM2			BIT(9)
+#define  USB_HIMR_CPWM			BIT(8)
+#define  USB_HIMR_HIGHDOK		BIT(7)	/*  High Queue DMA OK
+						    Interrupt */
+#define  USB_HIMR_MGNTDOK		BIT(6)	/*  Management Queue DMA OK
+						    Interrupt */
+#define  USB_HIMR_BKDOK			BIT(5)	/*  AC_BK DMA OK Interrupt */
+#define  USB_HIMR_BEDOK			BIT(4)	/*  AC_BE DMA OK Interrupt */
+#define  USB_HIMR_VIDOK			BIT(3)	/*  AC_VI DMA OK Interrupt */
+#define  USB_HIMR_VODOK			BIT(2)	/*  AC_VO DMA Interrupt */
+#define  USB_HIMR_RDU			BIT(1)	/*  Receive Descriptor
+						    Unavailable */
+#define  USB_HIMR_ROK			BIT(0)	/*  Receive DMA OK Interrupt */
+
+#define REG_USB_SPECIAL_OPTION		0xfe55
+#define REG_USB_DMA_AGG_TO		0xfe5b
+#define REG_USB_AGG_TO			0xfe5c
+#define REG_USB_AGG_TH			0xfe5d
+
+#define REG_NORMAL_SIE_VID		0xfe60	/* 0xfe60 - 0xfe61 */
+#define REG_NORMAL_SIE_PID		0xfe62	/* 0xfe62 - 0xfe63 */
+#define REG_NORMAL_SIE_OPTIONAL		0xfe64
+#define REG_NORMAL_SIE_EP		0xfe65	/* 0xfe65 - 0xfe67 */
+#define REG_NORMAL_SIE_EP_TX		0xfe66
+#define  NORMAL_SIE_EP_TX_HIGH_MASK	0x000f
+#define  NORMAL_SIE_EP_TX_NORMAL_MASK	0x00f0
+#define  NORMAL_SIE_EP_TX_LOW_MASK	0x0f00
+
+#define REG_NORMAL_SIE_PHY		0xfe68	/* 0xfe68 - 0xfe6b */
+#define REG_NORMAL_SIE_OPTIONAL2	0xfe6c
+#define REG_NORMAL_SIE_GPS_EP		0xfe6d	/* RTL8723 only */
+#define REG_NORMAL_SIE_MAC_ADDR		0xfe70	/* 0xfe70 - 0xfe75 */
+#define REG_NORMAL_SIE_STRING		0xfe80	/* 0xfe80 - 0xfedf */
+
+/* RF6052 registers */
+#define RF6052_REG_AC			0x00
+#define RF6052_REG_IQADJ_G1		0x01
+#define RF6052_REG_IQADJ_G2		0x02
+#define RF6052_REG_BS_PA_APSET_G1_G4	0x03
+#define RF6052_REG_BS_PA_APSET_G5_G8	0x04
+#define RF6052_REG_POW_TRSW		0x05
+#define RF6052_REG_GAIN_RX		0x06
+#define RF6052_REG_GAIN_TX		0x07
+#define RF6052_REG_TXM_IDAC		0x08
+#define RF6052_REG_IPA_G		0x09
+#define RF6052_REG_TXBIAS_G		0x0a
+#define RF6052_REG_TXPA_AG		0x0b
+#define RF6052_REG_IPA_A		0x0c
+#define RF6052_REG_TXBIAS_A		0x0d
+#define RF6052_REG_BS_PA_APSET_G9_G11	0x0e
+#define RF6052_REG_BS_IQGEN		0x0f
+#define RF6052_REG_MODE1		0x10
+#define RF6052_REG_MODE2		0x11
+#define RF6052_REG_RX_AGC_HP		0x12
+#define RF6052_REG_TX_AGC		0x13
+#define RF6052_REG_BIAS			0x14
+#define RF6052_REG_IPA			0x15
+#define RF6052_REG_TXBIAS		0x16
+#define RF6052_REG_POW_ABILITY		0x17
+#define RF6052_REG_MODE_AG		0x18	/* RF channel and BW switch */
+#define  MODE_AG_CHANNEL_MASK		0x3ff
+#define  MODE_AG_CHANNEL_20MHZ		BIT(10)
+
+#define RF6052_REG_TOP			0x19
+#define RF6052_REG_RX_G1		0x1a
+#define RF6052_REG_RX_G2		0x1b
+#define RF6052_REG_RX_BB2		0x1c
+#define RF6052_REG_RX_BB1		0x1d
+#define RF6052_REG_RCK1			0x1e
+#define RF6052_REG_RCK2			0x1f
+#define RF6052_REG_TX_G1		0x20
+#define RF6052_REG_TX_G2		0x21
+#define RF6052_REG_TX_G3		0x22
+#define RF6052_REG_TX_BB1		0x23
+#define RF6052_REG_T_METER		0x24
+#define RF6052_REG_SYN_G1		0x25	/* RF TX Power control */
+#define RF6052_REG_SYN_G2		0x26	/* RF TX Power control */
+#define RF6052_REG_SYN_G3		0x27	/* RF TX Power control */
+#define RF6052_REG_SYN_G4		0x28	/* RF TX Power control */
+#define RF6052_REG_SYN_G5		0x29	/* RF TX Power control */
+#define RF6052_REG_SYN_G6		0x2a	/* RF TX Power control */
+#define RF6052_REG_SYN_G7		0x2b	/* RF TX Power control */
+#define RF6052_REG_SYN_G8		0x2c	/* RF TX Power control */
+
+#define RF6052_REG_RCK_OS		0x30	/* RF TX PA control */
+
+#define RF6052_REG_TXPA_G1		0x31	/* RF TX PA control */
+#define RF6052_REG_TXPA_G2		0x32	/* RF TX PA control */
+#define RF6052_REG_TXPA_G3		0x33	/* RF TX PA control */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-29 21:18 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
@ 2015-08-30  4:42   ` Larry Finger
  2015-08-30 18:41     ` Jes Sorensen
  2015-08-31 14:48   ` Johannes Berg
  2015-10-08 16:23   ` Jakub Sitnicki
  2 siblings, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-08-30  4:42 UTC (permalink / raw)
  To: Jes.Sorensen, linux-wireless; +Cc: kvalo

On 08/29/2015 04:18 PM, Jes.Sorensen@redhat.com wrote:
> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>
> This is an alternate driver for a number of Realtek WiFi USB devices,
> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
> It was written from scratch utilizing the Linux mac80211 stack.
>
> After spending months cleaning up the vendor provided rtl8723au
> driver, which comes with it's own 802.11 stack included, I decided to
> rewrite this driver from the bottom up.
>
> Many thanks to Johannes Berg for 802.11 insights and help and Larry
> Finger for help with the vendor driver.
>
> The full git log for the development of this driver can be found here:
> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>      branch rtl8723au-mac80211
>
> This driver is still under development, but has proven to be very
> stable for me. It currently supports station mode only. It has support
> for OFDM and CCK rates, as well as AMPDU. It does lack certain
> features found in the staging driver, such as power management and
> 40MHz channel support. In addition it does not support AD-HOC, AP, and
> monitor mode support at this point.
>
> The driver is known to work with the following devices:
> Lenovo Yoga (rtl8723au)
> TP-Link TL-WN823N (rtl8192cu)
> Etekcity 6R (rtl8188cu)
> Daffodil LAN03 (rtl8188cu)
> Alfa AWUS036NHR (rtl8188ru)
>
> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>

I did not realize you were resubmitting this driver so soon. I have been 
accumulating some patches that I was going to send to you in the next couple of 
days. The most important of these are described inline below.

> ---
>   MAINTAINERS                          |    7 +
>   drivers/net/wireless/Kconfig         |   32 +
>   drivers/net/wireless/Makefile        |    2 +
>   drivers/net/wireless/rtl8xxxu.c      | 5829 ++++++++++++++++++++++++++++++++++
>   drivers/net/wireless/rtl8xxxu.h      |  597 ++++
>   drivers/net/wireless/rtl8xxxu_regs.h |  980 ++++++
>   6 files changed, 7447 insertions(+)
>   create mode 100644 drivers/net/wireless/rtl8xxxu.c
>   create mode 100644 drivers/net/wireless/rtl8xxxu.h
>   create mode 100644 drivers/net/wireless/rtl8xxxu_regs.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b60e2b2..54b03bd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -8699,6 +8699,13 @@ S:	Maintained
>   F:	drivers/net/wireless/rtlwifi/
>   F:	drivers/net/wireless/rtlwifi/rtl8192ce/
>
> +RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
> +M:	Jes Sorensen <Jes.Sorensen@redhat.com>
> +L:	linux-wireless@vger.kernel.org
> +T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
> +S:	Maintained
> +F:	drivers/net/wireless/rtl8xxxu*.[ch]
> +
>   S3 SAVAGE FRAMEBUFFER DRIVER
>   M:	Antonino Daplas <adaplas@gmail.com>
>   L:	linux-fbdev@vger.kernel.org
> diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
> index a63ab2e..def6cfd 100644
> --- a/drivers/net/wir/eless/Kconfig
> +++ b/drivers/net/wireless/Kconfig
> @@ -243,6 +243,38 @@ config ADM8211
>
>   	  Thanks to Infineon-ADMtek for their support of this driver.
>
> +config RTL8XXXU
> +	tristate "RTL8723AU/RTL8188[CR]U/RTL819[12]CU (mac80211) support"
> +	depends on MAC80211 && USB
> +	---help---
> +	  This is an alternative driver for various Realtek RTL8XXX
> +	  parts written to utilize the Linux mac80211 stack.
> +	  The driver is known to work with a number of RTL8723AU,
> +	  RL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU devices
> +
> +	  This driver is under development and has a limited feature
> +	  set. In particular it does not yet support 40MHz channels
> +	  and power management. However it should have a smaller
> +	  memory footprint than the vendor drivers and benetifs
> +	  from the in kernel mac80211 stack.
> +
> +	  It can coexist with drivers from drivers/staging/rtl8723au,
> +	  drivers/staging/rtl8192u, and drivers/net/wireless/rtlwifi,
> +	  but you will need to control which module you wish to load.
> +
> +	  To compile this driver as a module, choose M here: the module will
> +	  be called r8xxxu.  If unsure, say N.
> +
> +config RTL8XXXU_UNTESTED
> +	bool "Include support for untested Realtek 8xxx USB devices"
> +	depends on RTL8XXXU
> +	---help---
> +	  This option enables detection of Realtek 8723/8188/8191/8192 WiFi
> +	  USB devices which have not been tested directly by the driver
> +	  author or reported to be working by third parties.
> +
> +	  Please report your results!
> +
>   config MAC80211_HWSIM
>   	tristate "Simulated radio testing tool for mac80211"
>   	depends on MAC80211
> diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
> index 6b9e729..593bdef 100644
> --- a/drivers/net/wireless/Makefile
> +++ b/drivers/net/wireless/Makefile
> @@ -39,6 +39,8 @@ obj-$(CONFIG_LIBERTAS_THINFIRM)	+= libertas_tf/
>
>   obj-$(CONFIG_ADM8211)	+= adm8211.o
>
> +obj-$(CONFIG_RTL8XXXU)	+= rtl8xxxu.o
> +
>   obj-$(CONFIG_MWL8K)	+= mwl8k.o
>
>   obj-$(CONFIG_IWLWIFI)	+= iwlwifi/
> diff --git a/drivers/net/wireless/rtl8xxxu.c b/drivers/net/wireless/rtl8xxxu.c
> new file mode 100644
> index 0000000..6cc994b
> --- /dev/null
> +++ b/drivers/net/wireless/rtl8xxxu.c
> @@ -0,0 +1,5829 @@
> +/*
> + * RTL8XXXU mac80211 USB driver
> + *
> + * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
> + *
> + * Portions, notably calibration code:
> + * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
> + *
> + * This driver was written as a replacement for the vendor provided
> + * rtl8723au driver. As the Realtek 8xxx chips are very similar in
> + * their programming interface, I have started adding support for
> + * additional 8xxx chips like the 8192cu, 8188cus, etc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/spinlock.h>
> +#include <linux/list.h>
> +#include <linux/usb.h>
> +#include <linux/netdevice.h>
> +#include <linux/etherdevice.h>
> +#include <linux/ethtool.h>
> +#include <linux/wireless.h>
> +#include <linux/firmware.h>
> +#include <linux/moduleparam.h>
> +#include <net/mac80211.h>
> +#include "rtl8xxxu.h"
> +#include "rtl8xxxu_regs.h"
> +
> +#define DRIVER_NAME "rtl8xxxu"
> +
> +static int rtl8xxxu_debug = 0;

Checkpatch reports:

ERROR: do not initialise statics to 0 or NULL
#106: FILE: drivers/net/wireless/rtl8xxxu.c:45:
+static int rtl8xxxu_debug = 0;

> +
> +MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>");
> +MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin");
> +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin");
> +MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin");
> +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin");
> +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin");
> +MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin");
> +
> +module_param_named(debug, rtl8xxxu_debug, int, 0600);
> +MODULE_PARM_DESC(debug, "Set debug mask");
> +
> +#define USB_VENDOR_ID_REALTEK		0x0bda
> +/* Minimum IEEE80211_MAX_FRAME_LEN */
> +#define RTL_RX_BUFFER_SIZE		IEEE80211_MAX_FRAME_LEN
> +
> +static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
> +				  struct rtl8xxxu_rx_urb *rx_urb);
> +
> +static struct ieee80211_rate rtl8xxxu_rates[] = {
> +	{ .bitrate = 10, .hw_value = DESC_RATE_1M, .flags = 0 },
> +	{ .bitrate = 20, .hw_value = DESC_RATE_2M, .flags = 0 },
> +	{ .bitrate = 55, .hw_value = DESC_RATE_5_5M, .flags = 0 },
> +	{ .bitrate = 110, .hw_value = DESC_RATE_11M, .flags = 0 },
> +	{ .bitrate = 60, .hw_value = DESC_RATE_6M, .flags = 0 },
> +	{ .bitrate = 90, .hw_value = DESC_RATE_9M, .flags = 0 },
> +	{ .bitrate = 120, .hw_value = DESC_RATE_12M, .flags = 0 },
> +	{ .bitrate = 180, .hw_value = DESC_RATE_18M, .flags = 0 },
> +	{ .bitrate = 240, .hw_value = DESC_RATE_24M, .flags = 0 },
> +	{ .bitrate = 360, .hw_value = DESC_RATE_36M, .flags = 0 },
> +	{ .bitrate = 480, .hw_value = DESC_RATE_48M, .flags = 0 },
> +	{ .bitrate = 540, .hw_value = DESC_RATE_54M, .flags = 0 },
> +};
> +
> +static struct ieee80211_channel rtl8xxxu_channels_2g[] = {
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2412,
> +	  .hw_value = 1, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2417,
> +	  .hw_value = 2, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2422,
> +	  .hw_value = 3, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2427,
> +	  .hw_value = 4, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2432,
> +	  .hw_value = 5, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2437,
> +	  .hw_value = 6, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2442,
> +	  .hw_value = 7, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2447,
> +	  .hw_value = 8, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2452,
> +	  .hw_value = 9, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2457,
> +	  .hw_value = 10, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2462,
> +	  .hw_value = 11, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2467,
> +	  .hw_value = 12, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2472,
> +	  .hw_value = 13, .max_power = 30 },
> +	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2484,
> +	  .hw_value = 14, .max_power = 30 }
> +};
> +
> +static struct ieee80211_supported_band rtl8xxxu_supported_band = {
> +	.channels = rtl8xxxu_channels_2g,
> +	.n_channels = ARRAY_SIZE(rtl8xxxu_channels_2g),
> +	.bitrates = rtl8xxxu_rates,
> +	.n_bitrates = ARRAY_SIZE(rtl8xxxu_rates),
> +};
> +
> +static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = {
> +	{0x420, 0x80}, {0x423, 0x00}, {0x430, 0x00}, {0x431, 0x00},
> +	{0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05},
> +	{0x436, 0x06}, {0x437, 0x07}, {0x438, 0x00}, {0x439, 0x00},
> +	{0x43a, 0x00}, {0x43b, 0x01}, {0x43c, 0x04}, {0x43d, 0x05},
> +	{0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01},
> +	{0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f},
> +	{0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72},
> +	{0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x462, 0x08},
> +	{0x463, 0x03}, {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff},
> +	{0x4cd, 0xff}, {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2},
> +	{0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3},
> +	{0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4},
> +	{0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4},
> +	{0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a},
> +	{0x515, 0x10}, {0x516, 0x0a}, {0x517, 0x10}, {0x51a, 0x16},
> +	{0x524, 0x0f}, {0x525, 0x4f}, {0x546, 0x40}, {0x547, 0x00},
> +	{0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, {0x55a, 0x02},
> +	{0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a},
> +	{0x652, 0x20}, {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e},
> +	{0x63f, 0x0e}, {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43},
> +	{0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43},
> +	{0x70a, 0x65}, {0x70b, 0x87}, {0xffff, 0xff},
> +};
> +
> +static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = {
> +	{0x800, 0x80040000}, {0x804, 0x00000003},
> +	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
> +	{0x810, 0x10001331}, {0x814, 0x020c3d10},
> +	{0x818, 0x02200385}, {0x81c, 0x00000000},
> +	{0x820, 0x01000100}, {0x824, 0x00390004},
> +	{0x828, 0x00000000}, {0x82c, 0x00000000},
> +	{0x830, 0x00000000}, {0x834, 0x00000000},
> +	{0x838, 0x00000000}, {0x83c, 0x00000000},
> +	{0x840, 0x00010000}, {0x844, 0x00000000},
> +	{0x848, 0x00000000}, {0x84c, 0x00000000},
> +	{0x850, 0x00000000}, {0x854, 0x00000000},
> +	{0x858, 0x569a569a}, {0x85c, 0x001b25a4},
> +	{0x860, 0x66f60110}, {0x864, 0x061f0130},
> +	{0x868, 0x00000000}, {0x86c, 0x32323200},
> +	{0x870, 0x07000760}, {0x874, 0x22004000},
> +	{0x878, 0x00000808}, {0x87c, 0x00000000},
> +	{0x880, 0xc0083070}, {0x884, 0x000004d5},
> +	{0x888, 0x00000000}, {0x88c, 0xccc000c0},
> +	{0x890, 0x00000800}, {0x894, 0xfffffffe},
> +	{0x898, 0x40302010}, {0x89c, 0x00706050},
> +	{0x900, 0x00000000}, {0x904, 0x00000023},
> +	{0x908, 0x00000000}, {0x90c, 0x81121111},
> +	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
> +	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
> +	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
> +	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
> +	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
> +	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
> +	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
> +	{0xa78, 0x00000900},
> +	{0xc00, 0x48071d40}, {0xc04, 0x03a05611},
> +	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
> +	{0xc10, 0x08800000}, {0xc14, 0x40000100},
> +	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
> +	{0xc20, 0x00000000}, {0xc24, 0x00000000},
> +	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
> +	{0xc30, 0x69e9ac44}, {0xc34, 0x469652af},
> +	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
> +	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
> +	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
> +	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
> +	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
> +	{0xc60, 0x00000000}, {0xc64, 0x7112848b},
> +	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
> +	{0xc70, 0x2c7f000d}, {0xc74, 0x018610db},
> +	{0xc78, 0x0000001f}, {0xc7c, 0x00b91612},
> +	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
> +	{0xc88, 0x40000100}, {0xc8c, 0x20200000},
> +	{0xc90, 0x00121820}, {0xc94, 0x00000000},
> +	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
> +	{0xca0, 0x00000000}, {0xca4, 0x00000080},
> +	{0xca8, 0x00000000}, {0xcac, 0x00000000},
> +	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
> +	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
> +	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
> +	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
> +	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
> +	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
> +	{0xce0, 0x00222222}, {0xce4, 0x00000000},
> +	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
> +	{0xd00, 0x00080740}, {0xd04, 0x00020401},
> +	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
> +	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
> +	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
> +	{0xd30, 0x00000000}, {0xd34, 0x80608000},
> +	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
> +	{0xd40, 0x00000000}, {0xd44, 0x00000000},
> +	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
> +	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
> +	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
> +	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
> +	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
> +	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
> +	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
> +	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
> +	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
> +	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
> +	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
> +	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
> +	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
> +	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
> +	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
> +	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
> +	{0xe5c, 0x28160d05}, {0xe60, 0x00000008},
> +	{0xe68, 0x001b25a4}, {0xe6c, 0x631b25a0},
> +	{0xe70, 0x631b25a0}, {0xe74, 0x081b25a0},
> +	{0xe78, 0x081b25a0}, {0xe7c, 0x081b25a0},
> +	{0xe80, 0x081b25a0}, {0xe84, 0x631b25a0},
> +	{0xe88, 0x081b25a0}, {0xe8c, 0x631b25a0},
> +	{0xed0, 0x631b25a0}, {0xed4, 0x631b25a0},
> +	{0xed8, 0x631b25a0}, {0xedc, 0x001b25a0},
> +	{0xee0, 0x001b25a0}, {0xeec, 0x6b1b25a0},
> +	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
> +	{0xf00, 0x00000300},
> +	{0xffff, 0xffffffff},
> +};
> +
> +static struct rtl8xxxu_reg32val rtl8192cu_phy_2t_init_table[] = {
> +	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
> +	{0x800, 0x80040002}, {0x804, 0x00000003},
> +	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
> +	{0x810, 0x10000330}, {0x814, 0x020c3d10},
> +	{0x818, 0x02200385}, {0x81c, 0x00000000},
> +	{0x820, 0x01000100}, {0x824, 0x00390004},
> +	{0x828, 0x01000100}, {0x82c, 0x00390004},
> +	{0x830, 0x27272727}, {0x834, 0x27272727},
> +	{0x838, 0x27272727}, {0x83c, 0x27272727},
> +	{0x840, 0x00010000}, {0x844, 0x00010000},
> +	{0x848, 0x27272727}, {0x84c, 0x27272727},
> +	{0x850, 0x00000000}, {0x854, 0x00000000},
> +	{0x858, 0x569a569a}, {0x85c, 0x0c1b25a4},
> +	{0x860, 0x66e60230}, {0x864, 0x061f0130},
> +	{0x868, 0x27272727}, {0x86c, 0x2b2b2b27},
> +	{0x870, 0x07000700}, {0x874, 0x22184000},
> +	{0x878, 0x08080808}, {0x87c, 0x00000000},
> +	{0x880, 0xc0083070}, {0x884, 0x000004d5},
> +	{0x888, 0x00000000}, {0x88c, 0xcc0000c0},
> +	{0x890, 0x00000800}, {0x894, 0xfffffffe},
> +	{0x898, 0x40302010}, {0x89c, 0x00706050},
> +	{0x900, 0x00000000}, {0x904, 0x00000023},
> +	{0x908, 0x00000000}, {0x90c, 0x81121313},
> +	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
> +	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
> +	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
> +	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
> +	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
> +	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
> +	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
> +	{0xc00, 0x48071d40}, {0xc04, 0x03a05633},
> +	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
> +	{0xc10, 0x08800000}, {0xc14, 0x40000100},
> +	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
> +	{0xc20, 0x00000000}, {0xc24, 0x00000000},
> +	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
> +	{0xc30, 0x69e9ac44}, {0xc34, 0x469652cf},
> +	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
> +	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
> +	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
> +	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
> +	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
> +	{0xc60, 0x00000000}, {0xc64, 0x5116848b},
> +	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
> +	{0xc70, 0x2c7f000d}, {0xc74, 0x2186115b},
> +	{0xc78, 0x0000001f}, {0xc7c, 0x00b99612},
> +	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
> +	{0xc88, 0x40000100}, {0xc8c, 0xa0e40000},
> +	{0xc90, 0x00121820}, {0xc94, 0x00000000},
> +	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
> +	{0xca0, 0x00000000}, {0xca4, 0x00000080},
> +	{0xca8, 0x00000000}, {0xcac, 0x00000000},
> +	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
> +	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
> +	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
> +	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
> +	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
> +	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
> +	{0xce0, 0x00222222}, {0xce4, 0x00000000},
> +	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
> +	{0xd00, 0x00080740}, {0xd04, 0x00020403},
> +	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
> +	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
> +	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
> +	{0xd30, 0x00000000}, {0xd34, 0x80608000},
> +	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
> +	{0xd40, 0x00000000}, {0xd44, 0x00000000},
> +	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
> +	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
> +	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
> +	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
> +	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
> +	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
> +	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
> +	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
> +	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
> +	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
> +	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
> +	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
> +	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
> +	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
> +	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
> +	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
> +	{0xe5c, 0x28160d05}, {0xe60, 0x00000010},
> +	{0xe68, 0x001b25a4}, {0xe6c, 0x63db25a4},
> +	{0xe70, 0x63db25a4}, {0xe74, 0x0c1b25a4},
> +	{0xe78, 0x0c1b25a4}, {0xe7c, 0x0c1b25a4},
> +	{0xe80, 0x0c1b25a4}, {0xe84, 0x63db25a4},
> +	{0xe88, 0x0c1b25a4}, {0xe8c, 0x63db25a4},
> +	{0xed0, 0x63db25a4}, {0xed4, 0x63db25a4},
> +	{0xed8, 0x63db25a4}, {0xedc, 0x001b25a4},
> +	{0xee0, 0x001b25a4}, {0xeec, 0x6fdb25a4},
> +	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
> +	{0xf00, 0x00000300},
> +	{0xffff, 0xffffffff},
> +};
> +
> +static struct rtl8xxxu_reg32val rtl8188ru_phy_1t_highpa_table[] = {
> +	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
> +	{0x040, 0x000c0004}, {0x800, 0x80040000},
> +	{0x804, 0x00000001}, {0x808, 0x0000fc00},
> +	{0x80c, 0x0000000a}, {0x810, 0x10005388},
> +	{0x814, 0x020c3d10}, {0x818, 0x02200385},
> +	{0x81c, 0x00000000}, {0x820, 0x01000100},
> +	{0x824, 0x00390204}, {0x828, 0x00000000},
> +	{0x82c, 0x00000000}, {0x830, 0x00000000},
> +	{0x834, 0x00000000}, {0x838, 0x00000000},
> +	{0x83c, 0x00000000}, {0x840, 0x00010000},
> +	{0x844, 0x00000000}, {0x848, 0x00000000},
> +	{0x84c, 0x00000000}, {0x850, 0x00000000},
> +	{0x854, 0x00000000}, {0x858, 0x569a569a},
> +	{0x85c, 0x001b25a4}, {0x860, 0x66e60230},
> +	{0x864, 0x061f0130}, {0x868, 0x00000000},
> +	{0x86c, 0x20202000}, {0x870, 0x03000300},
> +	{0x874, 0x22004000}, {0x878, 0x00000808},
> +	{0x87c, 0x00ffc3f1}, {0x880, 0xc0083070},
> +	{0x884, 0x000004d5}, {0x888, 0x00000000},
> +	{0x88c, 0xccc000c0}, {0x890, 0x00000800},
> +	{0x894, 0xfffffffe}, {0x898, 0x40302010},
> +	{0x89c, 0x00706050}, {0x900, 0x00000000},
> +	{0x904, 0x00000023}, {0x908, 0x00000000},
> +	{0x90c, 0x81121111}, {0xa00, 0x00d047c8},
> +	{0xa04, 0x80ff000c}, {0xa08, 0x8c838300},
> +	{0xa0c, 0x2e68120f}, {0xa10, 0x9500bb78},
> +	{0xa14, 0x11144028}, {0xa18, 0x00881117},
> +	{0xa1c, 0x89140f00}, {0xa20, 0x15160000},
> +	{0xa24, 0x070b0f12}, {0xa28, 0x00000104},
> +	{0xa2c, 0x00d30000}, {0xa70, 0x101fbf00},
> +	{0xa74, 0x00000007}, {0xc00, 0x48071d40},
> +	{0xc04, 0x03a05611}, {0xc08, 0x000000e4},
> +	{0xc0c, 0x6c6c6c6c}, {0xc10, 0x08800000},
> +	{0xc14, 0x40000100}, {0xc18, 0x08800000},
> +	{0xc1c, 0x40000100}, {0xc20, 0x00000000},
> +	{0xc24, 0x00000000}, {0xc28, 0x00000000},
> +	{0xc2c, 0x00000000}, {0xc30, 0x69e9ac44},
> +	{0xc34, 0x469652cf}, {0xc38, 0x49795994},
> +	{0xc3c, 0x0a97971c}, {0xc40, 0x1f7c403f},
> +	{0xc44, 0x000100b7}, {0xc48, 0xec020107},
> +	{0xc4c, 0x007f037f}, {0xc50, 0x6954342e},
> +	{0xc54, 0x43bc0094}, {0xc58, 0x6954342f},
> +	{0xc5c, 0x433c0094}, {0xc60, 0x00000000},
> +	{0xc64, 0x5116848b}, {0xc68, 0x47c00bff},
> +	{0xc6c, 0x00000036}, {0xc70, 0x2c46000d},
> +	{0xc74, 0x018610db}, {0xc78, 0x0000001f},
> +	{0xc7c, 0x00b91612}, {0xc80, 0x24000090},
> +	{0xc84, 0x20f60000}, {0xc88, 0x24000090},
> +	{0xc8c, 0x20200000}, {0xc90, 0x00121820},
> +	{0xc94, 0x00000000}, {0xc98, 0x00121820},
> +	{0xc9c, 0x00007f7f}, {0xca0, 0x00000000},
> +	{0xca4, 0x00000080}, {0xca8, 0x00000000},
> +	{0xcac, 0x00000000}, {0xcb0, 0x00000000},
> +	{0xcb4, 0x00000000}, {0xcb8, 0x00000000},
> +	{0xcbc, 0x28000000}, {0xcc0, 0x00000000},
> +	{0xcc4, 0x00000000}, {0xcc8, 0x00000000},
> +	{0xccc, 0x00000000}, {0xcd0, 0x00000000},
> +	{0xcd4, 0x00000000}, {0xcd8, 0x64b22427},
> +	{0xcdc, 0x00766932}, {0xce0, 0x00222222},
> +	{0xce4, 0x00000000}, {0xce8, 0x37644302},
> +	{0xcec, 0x2f97d40c}, {0xd00, 0x00080740},
> +	{0xd04, 0x00020401}, {0xd08, 0x0000907f},
> +	{0xd0c, 0x20010201}, {0xd10, 0xa0633333},
> +	{0xd14, 0x3333bc43}, {0xd18, 0x7a8f5b6b},
> +	{0xd2c, 0xcc979975}, {0xd30, 0x00000000},
> +	{0xd34, 0x80608000}, {0xd38, 0x00000000},
> +	{0xd3c, 0x00027293}, {0xd40, 0x00000000},
> +	{0xd44, 0x00000000}, {0xd48, 0x00000000},
> +	{0xd4c, 0x00000000}, {0xd50, 0x6437140a},
> +	{0xd54, 0x00000000}, {0xd58, 0x00000000},
> +	{0xd5c, 0x30032064}, {0xd60, 0x4653de68},
> +	{0xd64, 0x04518a3c}, {0xd68, 0x00002101},
> +	{0xd6c, 0x2a201c16}, {0xd70, 0x1812362e},
> +	{0xd74, 0x322c2220}, {0xd78, 0x000e3c24},
> +	{0xe00, 0x24242424}, {0xe04, 0x24242424},
> +	{0xe08, 0x03902024}, {0xe10, 0x24242424},
> +	{0xe14, 0x24242424}, {0xe18, 0x24242424},
> +	{0xe1c, 0x24242424}, {0xe28, 0x00000000},
> +	{0xe30, 0x1000dc1f}, {0xe34, 0x10008c1f},
> +	{0xe38, 0x02140102}, {0xe3c, 0x681604c2},
> +	{0xe40, 0x01007c00}, {0xe44, 0x01004800},
> +	{0xe48, 0xfb000000}, {0xe4c, 0x000028d1},
> +	{0xe50, 0x1000dc1f}, {0xe54, 0x10008c1f},
> +	{0xe58, 0x02140102}, {0xe5c, 0x28160d05},
> +	{0xe60, 0x00000008}, {0xe68, 0x001b25a4},
> +	{0xe6c, 0x631b25a0}, {0xe70, 0x631b25a0},
> +	{0xe74, 0x081b25a0}, {0xe78, 0x081b25a0},
> +	{0xe7c, 0x081b25a0}, {0xe80, 0x081b25a0},
> +	{0xe84, 0x631b25a0}, {0xe88, 0x081b25a0},
> +	{0xe8c, 0x631b25a0}, {0xed0, 0x631b25a0},
> +	{0xed4, 0x631b25a0}, {0xed8, 0x631b25a0},
> +	{0xedc, 0x001b25a0}, {0xee0, 0x001b25a0},
> +	{0xeec, 0x6b1b25a0}, {0xee8, 0x31555448},
> +	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
> +	{0xf00, 0x00000300},
> +	{0xffff, 0xffffffff},
> +};
> +
> +static struct rtl8xxxu_reg32val rtl8xxx_agc_standard_table[] = {
> +	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
> +	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
> +	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
> +	{0xc78, 0x7a060001}, {0xc78, 0x79070001},
> +	{0xc78, 0x78080001}, {0xc78, 0x77090001},
> +	{0xc78, 0x760a0001}, {0xc78, 0x750b0001},
> +	{0xc78, 0x740c0001}, {0xc78, 0x730d0001},
> +	{0xc78, 0x720e0001}, {0xc78, 0x710f0001},
> +	{0xc78, 0x70100001}, {0xc78, 0x6f110001},
> +	{0xc78, 0x6e120001}, {0xc78, 0x6d130001},
> +	{0xc78, 0x6c140001}, {0xc78, 0x6b150001},
> +	{0xc78, 0x6a160001}, {0xc78, 0x69170001},
> +	{0xc78, 0x68180001}, {0xc78, 0x67190001},
> +	{0xc78, 0x661a0001}, {0xc78, 0x651b0001},
> +	{0xc78, 0x641c0001}, {0xc78, 0x631d0001},
> +	{0xc78, 0x621e0001}, {0xc78, 0x611f0001},
> +	{0xc78, 0x60200001}, {0xc78, 0x49210001},
> +	{0xc78, 0x48220001}, {0xc78, 0x47230001},
> +	{0xc78, 0x46240001}, {0xc78, 0x45250001},
> +	{0xc78, 0x44260001}, {0xc78, 0x43270001},
> +	{0xc78, 0x42280001}, {0xc78, 0x41290001},
> +	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
> +	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
> +	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
> +	{0xc78, 0x21300001}, {0xc78, 0x20310001},
> +	{0xc78, 0x06320001}, {0xc78, 0x05330001},
> +	{0xc78, 0x04340001}, {0xc78, 0x03350001},
> +	{0xc78, 0x02360001}, {0xc78, 0x01370001},
> +	{0xc78, 0x00380001}, {0xc78, 0x00390001},
> +	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
> +	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
> +	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
> +	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
> +	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
> +	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
> +	{0xc78, 0x7a460001}, {0xc78, 0x79470001},
> +	{0xc78, 0x78480001}, {0xc78, 0x77490001},
> +	{0xc78, 0x764a0001}, {0xc78, 0x754b0001},
> +	{0xc78, 0x744c0001}, {0xc78, 0x734d0001},
> +	{0xc78, 0x724e0001}, {0xc78, 0x714f0001},
> +	{0xc78, 0x70500001}, {0xc78, 0x6f510001},
> +	{0xc78, 0x6e520001}, {0xc78, 0x6d530001},
> +	{0xc78, 0x6c540001}, {0xc78, 0x6b550001},
> +	{0xc78, 0x6a560001}, {0xc78, 0x69570001},
> +	{0xc78, 0x68580001}, {0xc78, 0x67590001},
> +	{0xc78, 0x665a0001}, {0xc78, 0x655b0001},
> +	{0xc78, 0x645c0001}, {0xc78, 0x635d0001},
> +	{0xc78, 0x625e0001}, {0xc78, 0x615f0001},
> +	{0xc78, 0x60600001}, {0xc78, 0x49610001},
> +	{0xc78, 0x48620001}, {0xc78, 0x47630001},
> +	{0xc78, 0x46640001}, {0xc78, 0x45650001},
> +	{0xc78, 0x44660001}, {0xc78, 0x43670001},
> +	{0xc78, 0x42680001}, {0xc78, 0x41690001},
> +	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
> +	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
> +	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
> +	{0xc78, 0x21700001}, {0xc78, 0x20710001},
> +	{0xc78, 0x06720001}, {0xc78, 0x05730001},
> +	{0xc78, 0x04740001}, {0xc78, 0x03750001},
> +	{0xc78, 0x02760001}, {0xc78, 0x01770001},
> +	{0xc78, 0x00780001}, {0xc78, 0x00790001},
> +	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
> +	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
> +	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
> +	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
> +	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
> +	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
> +	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
> +	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
> +	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
> +	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
> +	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
> +	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
> +	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
> +	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
> +	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
> +	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
> +	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
> +	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
> +	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
> +	{0xffff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_reg32val rtl8xxx_agc_highpa_table[] = {
> +	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
> +	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
> +	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
> +	{0xc78, 0x7b060001}, {0xc78, 0x7b070001},
> +	{0xc78, 0x7b080001}, {0xc78, 0x7a090001},
> +	{0xc78, 0x790a0001}, {0xc78, 0x780b0001},
> +	{0xc78, 0x770c0001}, {0xc78, 0x760d0001},
> +	{0xc78, 0x750e0001}, {0xc78, 0x740f0001},
> +	{0xc78, 0x73100001}, {0xc78, 0x72110001},
> +	{0xc78, 0x71120001}, {0xc78, 0x70130001},
> +	{0xc78, 0x6f140001}, {0xc78, 0x6e150001},
> +	{0xc78, 0x6d160001}, {0xc78, 0x6c170001},
> +	{0xc78, 0x6b180001}, {0xc78, 0x6a190001},
> +	{0xc78, 0x691a0001}, {0xc78, 0x681b0001},
> +	{0xc78, 0x671c0001}, {0xc78, 0x661d0001},
> +	{0xc78, 0x651e0001}, {0xc78, 0x641f0001},
> +	{0xc78, 0x63200001}, {0xc78, 0x62210001},
> +	{0xc78, 0x61220001}, {0xc78, 0x60230001},
> +	{0xc78, 0x46240001}, {0xc78, 0x45250001},
> +	{0xc78, 0x44260001}, {0xc78, 0x43270001},
> +	{0xc78, 0x42280001}, {0xc78, 0x41290001},
> +	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
> +	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
> +	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
> +	{0xc78, 0x21300001}, {0xc78, 0x20310001},
> +	{0xc78, 0x06320001}, {0xc78, 0x05330001},
> +	{0xc78, 0x04340001}, {0xc78, 0x03350001},
> +	{0xc78, 0x02360001}, {0xc78, 0x01370001},
> +	{0xc78, 0x00380001}, {0xc78, 0x00390001},
> +	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
> +	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
> +	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
> +	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
> +	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
> +	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
> +	{0xc78, 0x7b460001}, {0xc78, 0x7b470001},
> +	{0xc78, 0x7b480001}, {0xc78, 0x7a490001},
> +	{0xc78, 0x794a0001}, {0xc78, 0x784b0001},
> +	{0xc78, 0x774c0001}, {0xc78, 0x764d0001},
> +	{0xc78, 0x754e0001}, {0xc78, 0x744f0001},
> +	{0xc78, 0x73500001}, {0xc78, 0x72510001},
> +	{0xc78, 0x71520001}, {0xc78, 0x70530001},
> +	{0xc78, 0x6f540001}, {0xc78, 0x6e550001},
> +	{0xc78, 0x6d560001}, {0xc78, 0x6c570001},
> +	{0xc78, 0x6b580001}, {0xc78, 0x6a590001},
> +	{0xc78, 0x695a0001}, {0xc78, 0x685b0001},
> +	{0xc78, 0x675c0001}, {0xc78, 0x665d0001},
> +	{0xc78, 0x655e0001}, {0xc78, 0x645f0001},
> +	{0xc78, 0x63600001}, {0xc78, 0x62610001},
> +	{0xc78, 0x61620001}, {0xc78, 0x60630001},
> +	{0xc78, 0x46640001}, {0xc78, 0x45650001},
> +	{0xc78, 0x44660001}, {0xc78, 0x43670001},
> +	{0xc78, 0x42680001}, {0xc78, 0x41690001},
> +	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
> +	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
> +	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
> +	{0xc78, 0x21700001}, {0xc78, 0x20710001},
> +	{0xc78, 0x06720001}, {0xc78, 0x05730001},
> +	{0xc78, 0x04740001}, {0xc78, 0x03750001},
> +	{0xc78, 0x02760001}, {0xc78, 0x01770001},
> +	{0xc78, 0x00780001}, {0xc78, 0x00790001},
> +	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
> +	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
> +	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
> +	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
> +	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
> +	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
> +	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
> +	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
> +	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
> +	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
> +	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
> +	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
> +	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
> +	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
> +	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
> +	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
> +	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
> +	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
> +	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
> +	{0xffff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
> +	{0x00, 0x00030159}, {0x01, 0x00031284},
> +	{0x02, 0x00098000}, {0x03, 0x00039c63},
> +	{0x04, 0x000210e7}, {0x09, 0x0002044f},
> +	{0x0a, 0x0001a3f1}, {0x0b, 0x00014787},
> +	{0x0c, 0x000896fe}, {0x0d, 0x0000e02c},
> +	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
> +	{0x19, 0x00000000}, {0x1a, 0x00030355},
> +	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
> +	{0x1d, 0x000a1250}, {0x1e, 0x0000024f},
> +	{0x1f, 0x00000000}, {0x20, 0x0000b614},
> +	{0x21, 0x0006c000}, {0x22, 0x00000000},
> +	{0x23, 0x00001558}, {0x24, 0x00000060},
> +	{0x25, 0x00000483}, {0x26, 0x0004f000},
> +	{0x27, 0x000ec7d9}, {0x28, 0x00057730},
> +	{0x29, 0x00004783}, {0x2a, 0x00000001},
> +	{0x2b, 0x00021334}, {0x2a, 0x00000000},
> +	{0x2b, 0x00000054}, {0x2a, 0x00000001},
> +	{0x2b, 0x00000808}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
> +	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
> +	{0x2b, 0x00000808}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
> +	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
> +	{0x2b, 0x00000808}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
> +	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
> +	{0x2b, 0x00000709}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
> +	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
> +	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
> +	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
> +	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
> +	{0x10, 0x0002000f}, {0x11, 0x000203f9},
> +	{0x10, 0x0003000f}, {0x11, 0x000ff500},
> +	{0x10, 0x00000000}, {0x11, 0x00000000},
> +	{0x10, 0x0008000f}, {0x11, 0x0003f100},
> +	{0x10, 0x0009000f}, {0x11, 0x00023100},
> +	{0x12, 0x00032000}, {0x12, 0x00071000},
> +	{0x12, 0x000b0000}, {0x12, 0x000fc000},
> +	{0x13, 0x000287b3}, {0x13, 0x000244b7},
> +	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
> +	{0x13, 0x00018493}, {0x13, 0x0001429b},
> +	{0x13, 0x00010299}, {0x13, 0x0000c29c},
> +	{0x13, 0x000081a0}, {0x13, 0x000040ac},
> +	{0x13, 0x00000020}, {0x14, 0x0001944c},
> +	{0x14, 0x00059444}, {0x14, 0x0009944c},
> +	{0x14, 0x000d9444}, {0x15, 0x0000f474},
> +	{0x15, 0x0004f477}, {0x15, 0x0008f455},
> +	{0x15, 0x000cf455}, {0x16, 0x00000339},
> +	{0x16, 0x00040339}, {0x16, 0x00080339},
> +	{0x16, 0x000c0366}, {0x00, 0x00010159},
> +	{0x18, 0x0000f401}, {0xfe, 0x00000000},
> +	{0xfe, 0x00000000}, {0x1f, 0x00000003},
> +	{0xfe, 0x00000000}, {0xfe, 0x00000000},
> +	{0x1e, 0x00000247}, {0x1f, 0x00000000},
> +	{0x00, 0x00030159},
> +	{0xff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = {
> +	{0x00, 0x00030159}, {0x01, 0x00031284},
> +	{0x02, 0x00098000}, {0x03, 0x00018c63},
> +	{0x04, 0x000210e7}, {0x09, 0x0002044f},
> +	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
> +	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
> +	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
> +	{0x19, 0x00000000}, {0x1a, 0x00010255},
> +	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
> +	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
> +	{0x1f, 0x00080001}, {0x20, 0x0000b614},
> +	{0x21, 0x0006c000}, {0x22, 0x00000000},
> +	{0x23, 0x00001558}, {0x24, 0x00000060},
> +	{0x25, 0x00000483}, {0x26, 0x0004f000},
> +	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
> +	{0x29, 0x00004783}, {0x2a, 0x00000001},
> +	{0x2b, 0x00021334}, {0x2a, 0x00000000},
> +	{0x2b, 0x00000054}, {0x2a, 0x00000001},
> +	{0x2b, 0x00000808}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
> +	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
> +	{0x2b, 0x00000808}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
> +	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
> +	{0x2b, 0x00000808}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
> +	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
> +	{0x2b, 0x00000709}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
> +	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
> +	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
> +	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
> +	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
> +	{0x10, 0x0002000f}, {0x11, 0x000203f9},
> +	{0x10, 0x0003000f}, {0x11, 0x000ff500},
> +	{0x10, 0x00000000}, {0x11, 0x00000000},
> +	{0x10, 0x0008000f}, {0x11, 0x0003f100},
> +	{0x10, 0x0009000f}, {0x11, 0x00023100},
> +	{0x12, 0x00032000}, {0x12, 0x00071000},
> +	{0x12, 0x000b0000}, {0x12, 0x000fc000},
> +	{0x13, 0x000287b3}, {0x13, 0x000244b7},
> +	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
> +	{0x13, 0x00018493}, {0x13, 0x0001429b},
> +	{0x13, 0x00010299}, {0x13, 0x0000c29c},
> +	{0x13, 0x000081a0}, {0x13, 0x000040ac},
> +	{0x13, 0x00000020}, {0x14, 0x0001944c},
> +	{0x14, 0x00059444}, {0x14, 0x0009944c},
> +	{0x14, 0x000d9444}, {0x15, 0x0000f424},
> +	{0x15, 0x0004f424}, {0x15, 0x0008f424},
> +	{0x15, 0x000cf424}, {0x16, 0x000e0330},
> +	{0x16, 0x000a0330}, {0x16, 0x00060330},
> +	{0x16, 0x00020330}, {0x00, 0x00010159},
> +	{0x18, 0x0000f401}, {0xfe, 0x00000000},
> +	{0xfe, 0x00000000}, {0x1f, 0x00080003},
> +	{0xfe, 0x00000000}, {0xfe, 0x00000000},
> +	{0x1e, 0x00044457}, {0x1f, 0x00080000},
> +	{0x00, 0x00030159},
> +	{0xff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_rfregval rtl8192cu_radiob_2t_init_table[] = {
> +	{0x00, 0x00030159}, {0x01, 0x00031284},
> +	{0x02, 0x00098000}, {0x03, 0x00018c63},
> +	{0x04, 0x000210e7}, {0x09, 0x0002044f},
> +	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
> +	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
> +	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
> +	{0x12, 0x00032000}, {0x12, 0x00071000},
> +	{0x12, 0x000b0000}, {0x12, 0x000fc000},
> +	{0x13, 0x000287af}, {0x13, 0x000244b7},
> +	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
> +	{0x13, 0x00018493}, {0x13, 0x00014297},
> +	{0x13, 0x00010295}, {0x13, 0x0000c298},
> +	{0x13, 0x0000819c}, {0x13, 0x000040a8},
> +	{0x13, 0x0000001c}, {0x14, 0x0001944c},
> +	{0x14, 0x00059444}, {0x14, 0x0009944c},
> +	{0x14, 0x000d9444}, {0x15, 0x0000f424},
> +	{0x15, 0x0004f424}, {0x15, 0x0008f424},
> +	{0x15, 0x000cf424}, {0x16, 0x000e0330},
> +	{0x16, 0x000a0330}, {0x16, 0x00060330},
> +	{0x16, 0x00020330},
> +	{0xff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_rfregval rtl8192cu_radioa_1t_init_table[] = {
> +	{0x00, 0x00030159}, {0x01, 0x00031284},
> +	{0x02, 0x00098000}, {0x03, 0x00018c63},
> +	{0x04, 0x000210e7}, {0x09, 0x0002044f},
> +	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
> +	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
> +	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
> +	{0x19, 0x00000000}, {0x1a, 0x00010255},
> +	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
> +	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
> +	{0x1f, 0x00080001}, {0x20, 0x0000b614},
> +	{0x21, 0x0006c000}, {0x22, 0x00000000},
> +	{0x23, 0x00001558}, {0x24, 0x00000060},
> +	{0x25, 0x00000483}, {0x26, 0x0004f000},
> +	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
> +	{0x29, 0x00004783}, {0x2a, 0x00000001},
> +	{0x2b, 0x00021334}, {0x2a, 0x00000000},
> +	{0x2b, 0x00000054}, {0x2a, 0x00000001},
> +	{0x2b, 0x00000808}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
> +	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
> +	{0x2b, 0x00000808}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
> +	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
> +	{0x2b, 0x00000808}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
> +	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
> +	{0x2b, 0x00000709}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
> +	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
> +	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
> +	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
> +	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
> +	{0x10, 0x0002000f}, {0x11, 0x000203f9},
> +	{0x10, 0x0003000f}, {0x11, 0x000ff500},
> +	{0x10, 0x00000000}, {0x11, 0x00000000},
> +	{0x10, 0x0008000f}, {0x11, 0x0003f100},
> +	{0x10, 0x0009000f}, {0x11, 0x00023100},
> +	{0x12, 0x00032000}, {0x12, 0x00071000},
> +	{0x12, 0x000b0000}, {0x12, 0x000fc000},
> +	{0x13, 0x000287b3}, {0x13, 0x000244b7},
> +	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
> +	{0x13, 0x00018493}, {0x13, 0x0001429b},
> +	{0x13, 0x00010299}, {0x13, 0x0000c29c},
> +	{0x13, 0x000081a0}, {0x13, 0x000040ac},
> +	{0x13, 0x00000020}, {0x14, 0x0001944c},
> +	{0x14, 0x00059444}, {0x14, 0x0009944c},
> +	{0x14, 0x000d9444}, {0x15, 0x0000f405},
> +	{0x15, 0x0004f405}, {0x15, 0x0008f405},
> +	{0x15, 0x000cf405}, {0x16, 0x000e0330},
> +	{0x16, 0x000a0330}, {0x16, 0x00060330},
> +	{0x16, 0x00020330}, {0x00, 0x00010159},
> +	{0x18, 0x0000f401}, {0xfe, 0x00000000},
> +	{0xfe, 0x00000000}, {0x1f, 0x00080003},
> +	{0xfe, 0x00000000}, {0xfe, 0x00000000},
> +	{0x1e, 0x00044457}, {0x1f, 0x00080000},
> +	{0x00, 0x00030159},
> +	{0xff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = {
> +	{0x00, 0x00030159}, {0x01, 0x00031284},
> +	{0x02, 0x00098000}, {0x03, 0x00018c63},
> +	{0x04, 0x000210e7}, {0x09, 0x0002044f},
> +	{0x0a, 0x0001adb0}, {0x0b, 0x00054867},
> +	{0x0c, 0x0008992e}, {0x0d, 0x0000e529},
> +	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
> +	{0x19, 0x00000000}, {0x1a, 0x00000255},
> +	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
> +	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
> +	{0x1f, 0x00080001}, {0x20, 0x0000b614},
> +	{0x21, 0x0006c000}, {0x22, 0x0000083c},
> +	{0x23, 0x00001558}, {0x24, 0x00000060},
> +	{0x25, 0x00000483}, {0x26, 0x0004f000},
> +	{0x27, 0x000ec7d9}, {0x28, 0x000977c0},
> +	{0x29, 0x00004783}, {0x2a, 0x00000001},
> +	{0x2b, 0x00021334}, {0x2a, 0x00000000},
> +	{0x2b, 0x00000054}, {0x2a, 0x00000001},
> +	{0x2b, 0x00000808}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
> +	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
> +	{0x2b, 0x00000808}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
> +	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
> +	{0x2b, 0x00000808}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
> +	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
> +	{0x2b, 0x00000709}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
> +	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
> +	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
> +	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
> +	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
> +	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
> +	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
> +	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
> +	{0x10, 0x0002000f}, {0x11, 0x000203f9},
> +	{0x10, 0x0003000f}, {0x11, 0x000ff500},
> +	{0x10, 0x00000000}, {0x11, 0x00000000},
> +	{0x10, 0x0008000f}, {0x11, 0x0003f100},
> +	{0x10, 0x0009000f}, {0x11, 0x00023100},
> +	{0x12, 0x000d8000}, {0x12, 0x00090000},
> +	{0x12, 0x00051000}, {0x12, 0x00012000},
> +	{0x13, 0x00028fb4}, {0x13, 0x00024fa8},
> +	{0x13, 0x000207a4}, {0x13, 0x0001c3b0},
> +	{0x13, 0x000183a4}, {0x13, 0x00014398},
> +	{0x13, 0x000101a4}, {0x13, 0x0000c198},
> +	{0x13, 0x000080a4}, {0x13, 0x00004098},
> +	{0x13, 0x00000000}, {0x14, 0x0001944c},
> +	{0x14, 0x00059444}, {0x14, 0x0009944c},
> +	{0x14, 0x000d9444}, {0x15, 0x0000f405},
> +	{0x15, 0x0004f405}, {0x15, 0x0008f405},
> +	{0x15, 0x000cf405}, {0x16, 0x000e0330},
> +	{0x16, 0x000a0330}, {0x16, 0x00060330},
> +	{0x16, 0x00020330}, {0x00, 0x00010159},
> +	{0x18, 0x0000f401}, {0xfe, 0x00000000},
> +	{0xfe, 0x00000000}, {0x1f, 0x00080003},
> +	{0xfe, 0x00000000}, {0xfe, 0x00000000},
> +	{0x1e, 0x00044457}, {0x1f, 0x00080000},
> +	{0x00, 0x00030159},
> +	{0xff, 0xffffffff}
> +};
> +
> +static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = {
> +	{	/* RF_A */
> +		.hssiparm1 = REG_FPGA0_XA_HSSI_PARM1,
> +		.hssiparm2 = REG_FPGA0_XA_HSSI_PARM2,
> +		.lssiparm = REG_FPGA0_XA_LSSI_PARM,
> +		.hspiread = REG_HSPI_XA_READBACK,
> +		.lssiread = REG_FPGA0_XA_LSSI_READBACK,
> +		.rf_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL,
> +	},
> +	{	/* RF_B */
> +		.hssiparm1 = REG_FPGA0_XB_HSSI_PARM1,
> +		.hssiparm2 = REG_FPGA0_XB_HSSI_PARM2,
> +		.lssiparm = REG_FPGA0_XB_LSSI_PARM,
> +		.hspiread = REG_HSPI_XB_READBACK,
> +		.lssiread = REG_FPGA0_XB_LSSI_READBACK,
> +		.rf_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL,
> +	},
> +};
> +
> +static const u32 rtl8723au_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = {
> +	REG_OFDM0_XA_RX_IQ_IMBALANCE,
> +	REG_OFDM0_XB_RX_IQ_IMBALANCE,
> +	REG_OFDM0_ENERGY_CCA_THRES,
> +	REG_OFDM0_AGCR_SSI_TABLE,
> +	REG_OFDM0_XA_TX_IQ_IMBALANCE,
> +	REG_OFDM0_XB_TX_IQ_IMBALANCE,
> +	REG_OFDM0_XC_TX_AFE,
> +	REG_OFDM0_XD_TX_AFE,
> +	REG_OFDM0_RX_IQ_EXT_ANTA
> +};
> +
> +static u8 rtl8xxxu_read8(struct rtl8xxxu_priv *priv, u16 addr)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int len;
> +	u8 data;
> +
> +	mutex_lock(&priv->usb_buf_mutex);
> +	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
> +			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
> +			      RTW_USB_CONTROL_MSG_TIMEOUT);
> +	data = priv->usb_buf.val8;
> +	mutex_unlock(&priv->usb_buf_mutex);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
> +		dev_info(&udev->dev, "%s(%04x)   = 0x%02x, len %i\n",
> +			 __func__, addr, data, len);
> +	return data;
> +}
> +
> +static u16 rtl8xxxu_read16(struct rtl8xxxu_priv *priv, u16 addr)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int len;
> +	u16 data;
> +
> +	mutex_lock(&priv->usb_buf_mutex);
> +	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
> +			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
> +			      RTW_USB_CONTROL_MSG_TIMEOUT);
> +	data = le16_to_cpu(priv->usb_buf.val16);
> +	mutex_unlock(&priv->usb_buf_mutex);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
> +		dev_info(&udev->dev, "%s(%04x)  = 0x%04x, len %i\n",
> +			 __func__, addr, data, len);
> +	return data;
> +}
> +
> +static u32 rtl8xxxu_read32(struct rtl8xxxu_priv *priv, u16 addr)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int len;
> +	u32 data;
> +
> +	mutex_lock(&priv->usb_buf_mutex);
> +	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
> +			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
> +			      RTW_USB_CONTROL_MSG_TIMEOUT);
> +	data = le32_to_cpu(priv->usb_buf.val32);
> +	mutex_unlock(&priv->usb_buf_mutex);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
> +		dev_info(&udev->dev, "%s(%04x)  = 0x%08x, len %i\n",
> +			 __func__, addr, data, len);
> +	return data;
> +}
> +
> +static int rtl8xxxu_write8(struct rtl8xxxu_priv *priv, u16 addr, u8 val)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int ret;
> +
> +	mutex_lock(&priv->usb_buf_mutex);
> +	priv->usb_buf.val8 = val;
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
> +			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
> +			      RTW_USB_CONTROL_MSG_TIMEOUT);
> +
> +	mutex_unlock(&priv->usb_buf_mutex);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
> +		dev_info(&udev->dev, "%s(%04x) = 0x%02x\n",
> +			 __func__, addr, val);
> +	return ret;
> +}
> +
> +static int rtl8xxxu_write16(struct rtl8xxxu_priv *priv, u16 addr, u16 val)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int ret;
> +
> +	mutex_lock(&priv->usb_buf_mutex);
> +	priv->usb_buf.val16 = cpu_to_le16(val);
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
> +			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
> +			      RTW_USB_CONTROL_MSG_TIMEOUT);
> +	mutex_unlock(&priv->usb_buf_mutex);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
> +		dev_info(&udev->dev, "%s(%04x) = 0x%04x\n",
> +			 __func__, addr, val);
> +	return ret;
> +}
> +
> +static int rtl8xxxu_write32(struct rtl8xxxu_priv *priv, u16 addr, u32 val)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int ret;
> +
> +	mutex_lock(&priv->usb_buf_mutex);
> +	priv->usb_buf.val32 = cpu_to_le32(val);
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
> +			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
> +			      RTW_USB_CONTROL_MSG_TIMEOUT);
> +	mutex_unlock(&priv->usb_buf_mutex);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
> +		dev_info(&udev->dev, "%s(%04x) = 0x%08x\n",
> +			 __func__, addr, val);
> +	return ret;
> +}
> +
> +static int
> +rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
> +{
> +	struct usb_device *udev = priv->udev;
> +	int ret;
> +
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
> +			      addr, 0, buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
> +		dev_info(&udev->dev, "%s(%04x) = %p, len 0x%02x\n",
> +			 __func__, addr, buf, len);
> +	return ret;
> +}
> +
> +static int
> +rtl8xxxu_slow_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
> +{
> +	u32 blocksize = sizeof(u32);
> +	u32 *buf4 = (u32 *)buf;
> +	int i, offset, count, remainder;
> +
> +	count = len / blocksize;
> +	remainder = len % blocksize;
> +
> +	for (i = 0; i < count; i++) {
> +		offset = i * blocksize;
> +		rtl8xxxu_write32(priv, (REG_FW_START_ADDRESS + offset),
> +				 buf4[i]);
> +	}
> +
> +	if (remainder) {
> +		offset = count * blocksize;
> +		buf += offset;
> +		for (i = 0; i < remainder; i++) {
> +			rtl8xxxu_write8(priv, (REG_FW_START_ADDRESS +
> +					       offset + i), *(buf + i));
> +		}
> +	}
> +
> +	return len;
> +}
> +
> +static u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv,
> +			       enum rtl8xxxu_rfpath path, u8 reg)
> +{
> +	u32 hssia, val32, retval;
> +
> +	hssia = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
> +	if (path != RF_A)
> +		val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm2);
> +	else
> +		val32 = hssia;
> +
> +	val32 &= ~FPGA0_HSSI_PARM2_ADDR_MASK;
> +	val32 |= (reg << FPGA0_HSSI_PARM2_ADDR_SHIFT);
> +	val32 |= FPGA0_HSSI_PARM2_EDGE_READ;
> +	hssia &= ~FPGA0_HSSI_PARM2_EDGE_READ;
> +	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
> +
> +	udelay(10);
> +
> +	rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].hssiparm2, val32);
> +	udelay(100);
> +
> +	hssia |= FPGA0_HSSI_PARM2_EDGE_READ;
> +	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
> +	udelay(10);
> +
> +	val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm1);
> +	if (val32 & FPGA0_HSSI_PARM1_PI)
> +		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hspiread);
> +	else
> +		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].lssiread);
> +
> +	retval &= 0xfffff;
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_READ)
> +		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
> +			 __func__, reg, retval);
> +	return retval;
> +}
> +
> +static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
> +				enum rtl8xxxu_rfpath path, u8 reg, u32 data)
> +{
> +	int ret, retval;
> +	u32 dataaddr;
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_WRITE)
> +		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
> +			 __func__, reg, data);
> +
> +	data &= FPGA0_LSSI_PARM_DATA_MASK;
> +	dataaddr = (reg << FPGA0_LSSI_PARM_ADDR_SHIFT) | data;
> +
> +	/* Use XB for path B */
> +	ret = rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].lssiparm, dataaddr);
> +	if (ret != sizeof(dataaddr))
> +		retval = -EIO;
> +	else
> +		retval = 0;
> +
> +	udelay(1);
> +
> +	return retval;
> +}
> +
> +static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	int mbox_nr, retry, retval = 0;
> +	int mbox_reg, mbox_ext_reg;
> +	u8 val8;
> +
> +	mbox_nr = priv->next_mbox;
> +
> +	mbox_reg = REG_HMBOX_0 + (mbox_nr * 4);
> +	mbox_ext_reg = REG_HMBOX_EXT_0 + (mbox_nr * 2);
> +
> +	mutex_lock(&priv->h2c_mutex);
> +	/*
> +	 * MBOX ready?
> +	 */
> +	retry = 100;
> +	do {
> +		val8 = rtl8xxxu_read8(priv, REG_HMTFR);
> +		if (!(val8 & BIT(mbox_nr)))
> +			break;
> +	} while (retry--);
> +
> +	if (!retry) {
> +		dev_dbg(dev, "%s: Mailbox busy\n", __func__);
> +		retval = -EBUSY;
> +		goto error;
> +	}
> +
> +	/*
> +	 * Need to swap as it's being swapped again by rtl8xxxu_write16/32()
> +	 */
> +	if (h2c->cmd.cmd & H2C_EXT) {
> +		rtl8xxxu_write16(priv, mbox_ext_reg,
> +				 le16_to_cpu(h2c->raw.ext));
> +		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
> +			dev_info(dev, "H2C_EXT %04x\n",
> +				 le16_to_cpu(h2c->raw.ext));
> +	}
> +	rtl8xxxu_write32(priv, mbox_reg, le32_to_cpu(h2c->raw.data));
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
> +		dev_info(dev, "H2C %08x\n", le32_to_cpu(h2c->raw.data));
> +
> +	priv->next_mbox = (mbox_nr + 1) % H2C_MAX_MBOX;
> +
> +error:
> +	mutex_unlock(&priv->h2c_mutex);
> +	return retval;
> +}
> +
> +static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	u32 val32;
> +
> +	val8 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
> +	val8 |= BIT(0) | BIT(3);
> +	rtl8xxxu_write8(priv, REG_SPS0_CTRL, val8);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
> +	val32 &= ~(BIT(4) | BIT(5));
> +	val32 |= BIT(3);
> +	if (priv->rf_paths == 2) {
> +		val32 &= ~(BIT(20) | BIT(21));
> +		val32 |= BIT(19);
> +	}
> +	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
> +	val32 &= ~OFDM_RF_PATH_TX_MASK;
> +	if (priv->tx_paths == 2)
> +		val32 |= OFDM_RF_PATH_TX_A | OFDM_RF_PATH_TX_B;
> +	else if (priv->rtlchip == 0x8192c || priv->rtlchip == 0x8191c)
> +		val32 |= OFDM_RF_PATH_TX_B;
> +	else
> +		val32 |= OFDM_RF_PATH_TX_A;
> +	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +	val32 &= ~FPGA_RF_MODE_JAPAN;
> +	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +
> +	if (priv->rf_paths == 2)
> +		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x63db25a0);
> +	else
> +		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x631b25a0);
> +
> +	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x32d95);
> +	if (priv->rf_paths == 2)
> +		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x32d95);
> +
> +#if 0
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE3);
> +	rtl8xxxu_write8(priv, REG_APSD_CTRL, 0x00);
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE2);
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE3);
> +#endif
> +	rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
> +}
> +
> +static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv)
> +{
> +	u8 sps0;
> +	u32 val32;
> +
> +	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
> +
> +	sps0 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
> +
> +	/* RF RX code for preamble power saving */
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
> +	val32 &= ~(BIT(3) | BIT(4) | BIT(5));
> +	if (priv->rf_paths == 2)
> +		val32 &= ~(BIT(19) | BIT(20) | BIT(21));
> +	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
> +
> +	/* Disable TX for four paths */
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
> +	val32 &= ~OFDM_RF_PATH_TX_MASK;
> +	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
> +
> +	/* Enable power saving */
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +	val32 |= FPGA_RF_MODE_JAPAN;
> +	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +
> +	/* AFE control register to power down bits [30:22] */
> +	if (priv->rf_paths == 2)
> +		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00db25a0);
> +	else
> +		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x001b25a0);
> +
> +	/* Power down RF module */
> +	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0);
> +	if (priv->rf_paths == 2)
> +		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0);
> +
> +	sps0 &= ~(BIT(0) | BIT(3));
> +	rtl8xxxu_write8(priv, REG_SPS0_CTRL, sps0);
> +}
> +
> +
> +static void rtl8723a_stop_tx_beacon(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +
> +	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
> +	val8 &= ~BIT(6);
> +	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
> +
> +	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 1, 0x64);
> +	val8 = rtl8xxxu_read8(priv, REG_TBTT_PROHIBIT + 2);
> +	val8 &= ~BIT(0);
> +	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8);
> +}
> +
> +
> +/*
> + * The rtl8723a has 3 channel groups for it's efuse settings. It only
> + * supports the 2.4GHz band, so channels 1 - 14:
> + *  group 0: channels 1 - 3
> + *  group 1: channels 4 - 9
> + *  group 2: channels 10 - 14
> + *
> + * Note: We index from 0 in the code
> + */
> +static int rtl8723a_channel_to_group(int channel)
> +{
> +	int group;
> +
> +	if (channel < 4)
> +		group = 0;
> +	else if (channel < 10)
> +		group = 1;
> +	else
> +		group = 2;
> +
> +	return group;
> +}
> +
> +static void rtl8723au_config_channel(struct ieee80211_hw *hw)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	u32 val32, rsr;
> +	u8 val8, opmode;
> +	bool ht = true;
> +	int sec_ch_above;
> +	int i;
> +
> +	for (i = RF_A; i < priv->rf_paths; i++) {
> +		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
> +		val32 &= ~MODE_AG_CHANNEL_MASK;
> +		val32 |= hw->conf.chandef.chan->hw_value;
> +		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
> +	}
> +
> +	opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE);
> +	rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
> +
> +	switch (hw->conf.chandef.width) {
> +	case NL80211_CHAN_WIDTH_20_NOHT:
> +		ht = false;
> +	case NL80211_CHAN_WIDTH_20:
> +		opmode |= BW_OPMODE_20MHZ;
> +		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +		val32 &= ~FPGA_RF_MODE;
> +		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
> +		val32 &= ~FPGA_RF_MODE;
> +		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
> +		val32 |= FPGA0_ANALOG2_20MHZ;
> +		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
> +		break;
> +	case NL80211_CHAN_WIDTH_40:
> +		if (hw->conf.chandef.center_freq1 >
> +		    hw->conf.chandef.chan->center_freq)
> +			sec_ch_above = 1;
> +		else
> +			sec_ch_above = 0;
> +
> +		opmode &= ~BW_OPMODE_20MHZ;
> +		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
> +		rsr &= ~RSR_RSC_BANDWIDTH_40M;
> +		if (sec_ch_above)
> +			rsr |= RSR_RSC_UPPER_SUB_CHANNEL;
> +		else
> +			rsr |= RSR_RSC_LOWER_SUB_CHANNEL;
> +		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +		val32 |= FPGA_RF_MODE;
> +		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
> +		val32 |= FPGA_RF_MODE;
> +		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
> +
> +		/*
> +		 * Set Control channel to upper or lower. These settings
> +		 * are required only for 40MHz
> +		 */
> +		val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM);
> +		val32 &= ~CCK0_SIDEBAND;
> +		if (!sec_ch_above)
> +			val32 |= CCK0_SIDEBAND;
> +		rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
> +		val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */
> +		if (sec_ch_above)
> +			val32 |= OFDM_LSTF_PRIME_CH_LOW;
> +		else
> +			val32 |= OFDM_LSTF_PRIME_CH_HIGH;
> +		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
> +		val32 &= ~FPGA0_ANALOG2_20MHZ;
> +		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
> +		val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL);
> +		if (sec_ch_above)
> +			val32 |= FPGA0_PS_UPPER_CHANNEL;
> +		else
> +			val32 |= FPGA0_PS_LOWER_CHANNEL;
> +		rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
> +		break;
> +
> +	default:
> +		break;
> +	}
> +
> +	if (ht)
> +		val8 = 0x0e;
> +	else
> +		val8 = 0x0a;
> +
> +	rtl8xxxu_write8(priv, REG_SIFS_CCK + 1, val8);
> +	rtl8xxxu_write8(priv, REG_SIFS_OFDM + 1, val8);
> +
> +	rtl8xxxu_write16(priv, REG_R2T_SIFS, 0x0808);
> +	rtl8xxxu_write16(priv, REG_T2T_SIFS, 0x0a0a);
> +
> +	for (i = RF_A; i < priv->rf_paths; i++) {
> +		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
> +		if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40)
> +			val32 &= ~MODE_AG_CHANNEL_20MHZ;
> +		else
> +			val32 |= MODE_AG_CHANNEL_20MHZ;
> +		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
> +	}
> +}
> +
> +static void
> +rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
> +{
> +	u8 cck[RTL8723A_MAX_RF_PATHS], ofdm[RTL8723A_MAX_RF_PATHS];
> +	u8 ofdmbase[RTL8723A_MAX_RF_PATHS], mcsbase[RTL8723A_MAX_RF_PATHS];
> +	u32 val32, ofdm_a, ofdm_b, mcs_a, mcs_b;
> +	u8 val8;
> +	int group, i;
> +
> +	group = rtl8723a_channel_to_group(channel);
> +
> +	cck[0] = priv->cck_tx_power_index_A[group];
> +	ofdm[0] = priv->ht40_1s_tx_power_index_A[group];
> +
> +	if (priv->rf_paths > 1) {
> +		cck[1] = priv->cck_tx_power_index_B[group];
> +		ofdm[1] = priv->ht40_1s_tx_power_index_B[group];
> +	} else {
> +		cck[1] = 0;
> +		ofdm[1] = 0;
> +	}
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
> +		dev_info(&priv->udev->dev,
> +			 "%s: Setting TX power CCK A: %02x, "
> +			 "CCK B: %02x, OFDM A: %02x, OFDM B: %02x\n",
> +			 __func__, cck[0], cck[1], ofdm[0], ofdm[1]);
> +
> +	for (i = 0; i < RTL8723A_MAX_RF_PATHS; i++) {
> +		if (cck[i] > RF6052_MAX_TX_PWR)
> +			cck[i] = RF6052_MAX_TX_PWR;
> +		if (ofdm[i] > RF6052_MAX_TX_PWR)
> +			ofdm[i] = RF6052_MAX_TX_PWR;
> +	}
> +
> +	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32);
> +	val32 &= 0xffff00ff;
> +	val32 |= (cck[0] << 8);
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
> +	val32 &= 0xff;
> +	val32 |= ((cck[0] << 8) | (cck[0] << 16) | (cck[0] << 24));
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
> +	val32 &= 0xffffff00;
> +	val32 |= cck[1];
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK1_55_MCS32);
> +	val32 &= 0xff;
> +	val32 |= ((cck[1] << 8) | (cck[1] << 16) | (cck[1] << 24));
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK1_55_MCS32, val32);
> +
> +	ofdmbase[0] = ofdm[0] +	priv->ofdm_tx_power_index_diff[group].a;
> +	mcsbase[0] = ofdm[0];
> +	if (!ht40)
> +		mcsbase[0] += priv->ht20_tx_power_index_diff[group].a;
> +
> +	ofdmbase[1] = ofdm[1] +	priv->ofdm_tx_power_index_diff[group].b;
> +	mcsbase[1] = ofdm[1];
> +	if (!ht40)
> +		mcsbase[1] += priv->ht20_tx_power_index_diff[group].b;
> +
> +	ofdm_a = ofdmbase[0] | ofdmbase[0] << 8 |
> +		ofdmbase[0] << 16 | ofdmbase[0] << 24;
> +	ofdm_b = ofdmbase[1] | ofdmbase[1] << 8 |
> +		ofdmbase[1] << 16 | ofdmbase[1] << 24;
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm_a);
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm_b);
> +
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm_a);
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm_b);
> +
> +	mcs_a = mcsbase[0] | mcsbase[0] << 8 |
> +		mcsbase[0] << 16 | mcsbase[0] << 24;
> +	mcs_b = mcsbase[1] | mcsbase[1] << 8 |
> +		mcsbase[1] << 16 | mcsbase[1] << 24;
> +
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs_a);
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs_b);
> +
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs_a);
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs_b);
> +
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs_a);
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs_b);
> +
> +	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs_a);
> +	for (i = 0; i < 3; i++) {
> +		if (i != 2)
> +			val8 = (mcsbase[0] > 8) ? (mcsbase[0] - 8) : 0;
> +		else
> +			val8 = (mcsbase[0] > 6) ? (mcsbase[0] - 6) : 0;
> +		rtl8xxxu_write8(priv, REG_OFDM0_XC_TX_IQ_IMBALANCE + i, val8);
> +	}
> +	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs_b);
> +	for (i = 0; i < 3; i++) {
> +		if (i != 2)
> +			val8 = (mcsbase[1] > 8) ? (mcsbase[1] - 8) : 0;
> +		else
> +			val8 = (mcsbase[1] > 6) ? (mcsbase[1] - 6) : 0;
> +		rtl8xxxu_write8(priv, REG_OFDM0_XD_TX_IQ_IMBALANCE + i, val8);
> +	}
> +}
> +
> +static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
> +				  enum nl80211_iftype linktype)
> +{
> +	u16 val8;
> +
> +	val8 = rtl8xxxu_read16(priv, REG_MSR);
> +	val8 &= ~MSR_LINKTYPE_MASK;
> +
> +	switch (linktype) {
> +	case NL80211_IFTYPE_UNSPECIFIED:
> +		val8 |= MSR_LINKTYPE_NONE;
> +		break;
> +	case NL80211_IFTYPE_ADHOC:
> +		val8 |= MSR_LINKTYPE_ADHOC;
> +		break;
> +	case NL80211_IFTYPE_STATION:
> +		val8 |= MSR_LINKTYPE_STATION;
> +		break;
> +	case NL80211_IFTYPE_AP:
> +		val8 |= MSR_LINKTYPE_AP;
> +		break;
> +	default:
> +		goto out;
> +	}
> +
> +	rtl8xxxu_write8(priv, REG_MSR, val8);
> +out:
> +	return;
> +}
> +
> +static void
> +rtl8xxxu_set_retry(struct rtl8xxxu_priv *priv, u16 short_retry, u16 long_retry)
> +{
> +	u16 val16;
> +
> +	val16 = ((short_retry << RETRY_LIMIT_SHORT_SHIFT) &
> +		 RETRY_LIMIT_SHORT_MASK) |
> +		((long_retry << RETRY_LIMIT_LONG_SHIFT) &
> +		 RETRY_LIMIT_LONG_MASK);
> +
> +	rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
> +}
> +
> +static void
> +rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm)
> +{
> +	u16 val16;
> +
> +	val16 = ((cck << SPEC_SIFS_CCK_SHIFT) & SPEC_SIFS_CCK_MASK) |
> +		((ofdm << SPEC_SIFS_OFDM_SHIFT) & SPEC_SIFS_OFDM_MASK);
> +
> +	rtl8xxxu_write16(priv, REG_SPEC_SIFS, val16);
> +}
> +
> +static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	char *cut;
> +
> +	switch (priv->chip_cut) {
> +	case 0:
> +		cut = "A";
> +		break;
> +	case 1:
> +		cut = "B";
> +		break;
> +	default:
> +		cut = "unknown";
> +	}
> +
> +	dev_info(dev,
> +		 "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n",
> +		 priv->chip_name, cut, priv->vendor_umc ? "UMC" : "TSMC",
> +		 priv->tx_paths, priv->rx_paths, priv->ep_tx_count,
> +		 priv->has_wifi, priv->has_bluetooth, priv->has_gps,
> +		 priv->hi_pa);
> +
> +	dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr);
> +}
> +
> +static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	u32 val32, bonding;
> +	u16 val16;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_SYS_CFG);
> +	priv->chip_cut = (val32 & SYS_CFG_CHIP_VERSION_MASK) >>
> +		SYS_CFG_CHIP_VERSION_SHIFT;
> +	if (val32 & SYS_CFG_TRP_VAUX_EN) {
> +		dev_info(dev, "Unsupported test chip\n");
> +		return -ENOTSUPP;
> +	}
> +
> +	if (val32 & SYS_CFG_BT_FUNC) {
> +		sprintf(priv->chip_name, "8723AU");
> +		priv->rf_paths = 1;
> +		priv->rx_paths = 1;
> +		priv->tx_paths = 1;
> +		priv->rtlchip = 0x8723a;
> +
> +		val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL);
> +		if (val32 & MULTI_WIFI_FUNC_EN)
> +			priv->has_wifi = 1;
> +		if (val32 & MULTI_BT_FUNC_EN)
> +			priv->has_bluetooth = 1;
> +		if (val32 & MULTI_GPS_FUNC_EN)
> +			priv->has_gps = 1;
> +	} else if (val32 & SYS_CFG_TYPE_ID) {
> +		bonding = rtl8xxxu_read32(priv, REG_HPON_FSM);
> +		bonding &= HPON_FSM_BONDING_MASK;
> +		if (bonding == HPON_FSM_BONDING_1T2R) {
> +			sprintf(priv->chip_name, "8191CU");
> +			priv->rf_paths = 2;
> +			priv->rx_paths = 2;
> +			priv->tx_paths = 1;
> +			priv->rtlchip = 0x8191c;
> +		} else {
> +			sprintf(priv->chip_name, "8192CU");
> +			priv->rf_paths = 2;
> +			priv->rx_paths = 2;
> +			priv->tx_paths = 2;
> +			priv->rtlchip = 0x8192c;
> +		}
> +		priv->has_wifi = 1;
> +	} else {
> +		sprintf(priv->chip_name, "8188CU");
> +		priv->rf_paths = 1;
> +		priv->rx_paths = 1;
> +		priv->tx_paths = 1;
> +		priv->rtlchip = 0x8188c;
> +		priv->has_wifi = 1;
> +	}
> +
> +	if (val32 & SYS_CFG_VENDOR_ID)
> +		priv->vendor_umc = 1;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS);
> +	priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28;
> +
> +	val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX);
> +	if (val16 & NORMAL_SIE_EP_TX_HIGH_MASK) {
> +		priv->ep_tx_high_queue = 1;
> +		priv->ep_tx_count++;
> +	}
> +
> +	if (val16 & NORMAL_SIE_EP_TX_NORMAL_MASK) {
> +		priv->ep_tx_normal_queue = 1;
> +		priv->ep_tx_count++;
> +	}
> +
> +	if (val16 & NORMAL_SIE_EP_TX_LOW_MASK) {
> +		priv->ep_tx_low_queue = 1;
> +		priv->ep_tx_count++;
> +	}
> +
> +	/*
> +	 * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX
> +	 */
> +	if (!priv->ep_tx_count) {
> +		switch (priv->nr_out_eps) {
> +		case 3:
> +			priv->ep_tx_low_queue = 1;
> +			priv->ep_tx_count++;
> +		case 2:
> +			priv->ep_tx_normal_queue = 1;
> +			priv->ep_tx_count++;
> +		case 1:
> +			priv->ep_tx_high_queue = 1;
> +			priv->ep_tx_count++;
> +			break;
> +		default:
> +			dev_info(dev, "Unsupported USB TX end-points\n");
> +			return -ENOTSUPP;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
> +{
> +	if (priv->efuse_wifi.efuse8723.rtl_id != cpu_to_le16(0x8129))
> +		return -EINVAL;
> +
> +	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723.mac_addr);
> +
> +	memcpy(priv->cck_tx_power_index_A,
> +	       priv->efuse_wifi.efuse8723.cck_tx_power_index_A,
> +	       sizeof(priv->cck_tx_power_index_A));
> +	memcpy(priv->cck_tx_power_index_B,
> +	       priv->efuse_wifi.efuse8723.cck_tx_power_index_B,
> +	       sizeof(priv->cck_tx_power_index_B));
> +
> +	memcpy(priv->ht40_1s_tx_power_index_A,
> +	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_A,
> +	       sizeof(priv->ht40_1s_tx_power_index_A));
> +	memcpy(priv->ht40_1s_tx_power_index_B,
> +	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_B,
> +	       sizeof(priv->ht40_1s_tx_power_index_B));
> +
> +	memcpy(priv->ht20_tx_power_index_diff,
> +	       priv->efuse_wifi.efuse8723.ht20_tx_power_index_diff,
> +	       sizeof(priv->ht20_tx_power_index_diff));
> +	memcpy(priv->ofdm_tx_power_index_diff,
> +	       priv->efuse_wifi.efuse8723.ofdm_tx_power_index_diff,
> +	       sizeof(priv->ofdm_tx_power_index_diff));
> +
> +	memcpy(priv->ht40_max_power_offset,
> +	       priv->efuse_wifi.efuse8723.ht40_max_power_offset,
> +	       sizeof(priv->ht40_max_power_offset));
> +	memcpy(priv->ht20_max_power_offset,
> +	       priv->efuse_wifi.efuse8723.ht20_max_power_offset,
> +	       sizeof(priv->ht20_max_power_offset));
> +
> +	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
> +		 priv->efuse_wifi.efuse8723.vendor_name);
> +	dev_info(&priv->udev->dev, "Product: %.41s\n",
> +		 priv->efuse_wifi.efuse8723.device_name);
> +	return 0;
> +}
> +
> +static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
> +{
> +	int i;
> +
> +	if (priv->efuse_wifi.efuse8192.rtl_id != cpu_to_le16(0x8129))
> +		return -EINVAL;
> +
> +	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192.mac_addr);
> +
> +	memcpy(priv->cck_tx_power_index_A,
> +	       priv->efuse_wifi.efuse8192.cck_tx_power_index_A,
> +	       sizeof(priv->cck_tx_power_index_A));
> +	memcpy(priv->cck_tx_power_index_B,
> +	       priv->efuse_wifi.efuse8192.cck_tx_power_index_B,
> +	       sizeof(priv->cck_tx_power_index_B));
> +
> +	memcpy(priv->ht40_1s_tx_power_index_A,
> +	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_A,
> +	       sizeof(priv->ht40_1s_tx_power_index_A));
> +	memcpy(priv->ht40_1s_tx_power_index_B,
> +	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_B,
> +	       sizeof(priv->ht40_1s_tx_power_index_B));
> +	memcpy(priv->ht40_2s_tx_power_index_diff,
> +	       priv->efuse_wifi.efuse8192.ht40_2s_tx_power_index_diff,
> +	       sizeof(priv->ht40_2s_tx_power_index_diff));
> +
> +	memcpy(priv->ht20_tx_power_index_diff,
> +	       priv->efuse_wifi.efuse8192.ht20_tx_power_index_diff,
> +	       sizeof(priv->ht20_tx_power_index_diff));
> +	memcpy(priv->ofdm_tx_power_index_diff,
> +	       priv->efuse_wifi.efuse8192.ofdm_tx_power_index_diff,
> +	       sizeof(priv->ofdm_tx_power_index_diff));
> +
> +	memcpy(priv->ht40_max_power_offset,
> +	       priv->efuse_wifi.efuse8192.ht40_max_power_offset,
> +	       sizeof(priv->ht40_max_power_offset));
> +	memcpy(priv->ht20_max_power_offset,
> +	       priv->efuse_wifi.efuse8192.ht20_max_power_offset,
> +	       sizeof(priv->ht20_max_power_offset));
> +
> +	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
> +		 priv->efuse_wifi.efuse8192.vendor_name);
> +	dev_info(&priv->udev->dev, "Product: %.20s\n",
> +		 priv->efuse_wifi.efuse8192.device_name);
> +
> +	if (priv->efuse_wifi.efuse8192.rf_regulatory & 0x20) {
> +		sprintf(priv->chip_name, "8188RU");
> +		priv->hi_pa = 1;
> +	}
> +
> +	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02lx bytes):\n",
> +		 __func__, sizeof(struct rtl8192cu_efuse));

On a 32-bit PowerPC, the above line outputs the following:

warning: format ‘%lx’ expects argument of type ‘long unsigned int’, but argument 
4 has type ‘unsigned int’ [-Wformat]

This issue does not affect the object code, but it should be fixed. Setting the 
format specifier to %02x and adding a cast of (int) before the "size_of" will 
fix it on both sets of systems.

> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
> +		unsigned char *raw = priv->efuse_wifi.raw;
> +
> +		for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) {
> +			dev_info(&priv->udev->dev, "%02x: "
> +				 "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
> +				 raw[i], raw[i + 1], raw[i + 2],
> +				 raw[i + 3], raw[i + 4], raw[i + 5],
> +				 raw[i + 6], raw[i + 7]);
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int
> +rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data)
> +{
> +	int i;
> +	u8 val8;
> +	u32 val32;
> +
> +	/* Write Address */
> +	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 1, offset & 0xff);
> +	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 2);
> +	val8 &= 0xfc;
> +	val8 |= (offset >> 8) & 0x03;
> +	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 2, val8);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 3);
> +	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 3, val8 & 0x7f);
> +
> +	/* Poll for data read */
> +	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
> +	for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) {
> +		val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
> +		if (val32 & BIT(31))
> +			break;
> +	}
> +
> +	if (i == RTL8XXXU_MAX_REG_POLL)
> +		return -EIO;
> +
> +	udelay(50);
> +	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
> +
> +	*data = val32 & 0xff;
> +	return 0;
> +}
> +
> +static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	int i, ret = 0;
> +	u8 val8, word_mask, header, extheader;
> +	u16 val16, efuse_addr, offset;
> +	u32 val32;
> +
> +	val16 = rtl8xxxu_read16(priv, REG_9346CR);
> +	if (val16 & EEPROM_ENABLE)
> +		priv->has_eeprom = 1;
> +	if (val16 & EEPROM_BOOT)
> +		priv->boot_eeprom = 1;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST);
> +	val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT;
> +	rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32);
> +
> +	dev_dbg(dev, "Booting from %s\n",
> +		priv->boot_eeprom ? "EEPROM" : "EFUSE");
> +
> +	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_ENABLE);
> +
> +	/*  1.2V Power: From VDDON with Power Cut(0x0000[15]), default valid */
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
> +	if (!(val16 & SYS_ISO_PWC_EV12V)) {
> +		val16 |= SYS_ISO_PWC_EV12V;
> +		rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
> +	}
> +	/*  Reset: 0x0000[28], default valid */
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
> +	if (!(val16 & SYS_FUNC_ELDR)) {
> +		val16 |= SYS_FUNC_ELDR;
> +		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
> +	}
> +
> +	/*
> +	 * Clock: Gated(0x0008[5]) 8M(0x0008[1]) clock from ANA, default valid
> +	 */
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR);
> +	if (!(val16 & SYS_CLK_LOADER_ENABLE) || !(val16 & SYS_CLK_ANA8M)) {
> +		val16 |= (SYS_CLK_LOADER_ENABLE | SYS_CLK_ANA8M);
> +		rtl8xxxu_write16(priv, REG_SYS_CLKR, val16);
> +	}
> +
> +	/* Default value is 0xff */
> +	memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN_8723A);
> +
> +	efuse_addr = 0;
> +	while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) {
> +		ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &header);
> +		if (ret || header == 0xff)
> +			goto exit;
> +
> +		if ((header & 0x1f) == 0x0f) {	/* extended header */
> +			offset = (header & 0xe0) >> 5;
> +
> +			ret = rtl8xxxu_read_efuse8(priv, efuse_addr++,
> +						   &extheader);
> +			if (ret)
> +				goto exit;
> +			/* All words disabled */
> +			if ((extheader & 0x0f) == 0x0f)
> +				continue;
> +
> +			offset |= ((extheader & 0xf0) >> 1);
> +			word_mask = extheader & 0x0f;
> +		} else {
> +			offset = (header >> 4) & 0x0f;
> +			word_mask = header & 0x0f;
> +		}
> +
> +		if (offset < EFUSE_MAX_SECTION_8723A) {
> +			u16 map_addr;
> +			/* Get word enable value from PG header */
> +
> +			/* We have 8 bits to indicate validity */
> +			map_addr = offset * 8;
> +			if (map_addr >= EFUSE_MAP_LEN_8723A) {
> +				dev_warn(dev, "%s: Illegal map_addr (%04x), "
> +					 "efuse corrupt!\n",
> +					 __func__, map_addr);
> +				ret = -EINVAL;
> +				goto exit;
> +			}
> +			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
> +				/* Check word enable condition in the section */
> +				if (!(word_mask & BIT(i))) {
> +					ret = rtl8xxxu_read_efuse8(priv,
> +								   efuse_addr++,
> +								   &val8);
> +					if (ret)
> +						goto exit;
> +					priv->efuse_wifi.raw[map_addr++] = val8;
> +
> +					ret = rtl8xxxu_read_efuse8(priv,
> +								   efuse_addr++,
> +								   &val8);
> +					if (ret)
> +						goto exit;
> +					priv->efuse_wifi.raw[map_addr++] = val8;
> +				} else
> +					map_addr += 2;
> +			}
> +		} else {
> +			dev_warn(dev,
> +				 "%s: Illegal offset (%04x), efuse corrupt!\n",
> +				 __func__, offset);
> +			ret = -EINVAL;
> +			goto exit;
> +		}
> +	}
> +
> +exit:
> +	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_DISABLE);
> +
> +	return ret;
> +}
> +
> +static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	int ret = 0, i;
> +	u32 val32;
> +
> +	/* Poll checksum report */
> +	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
> +		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
> +		if (val32 & MCU_FW_DL_CSUM_REPORT)
> +			break;
> +	}
> +
> +	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
> +		dev_warn(dev, "Firmware checksum poll timed out\n");
> +		ret = -EAGAIN;
> +		goto exit;
> +	}
> +
> +	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
> +	val32 |= MCU_FW_DL_READY;
> +	val32 &= ~MCU_WINT_INIT_READY;
> +	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32);
> +
> +	/* Wait for firmware to become ready */
> +	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
> +		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
> +		if (val32 & MCU_WINT_INIT_READY)
> +			break;
> +
> +		udelay(100);
> +	}
> +
> +	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
> +		dev_warn(dev, "Firmware failed to start\n");
> +		ret = -EAGAIN;
> +		goto exit;
> +	}
> +
> +exit:
> +	return ret;
> +}
> +
> +static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
> +{
> +	int pages, remainder, i, ret;
> +	u8 val8;
> +	u16 val16;
> +	u32 val32;
> +	u8 *fwptr;
> +
> +	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1);
> +	val8 |= 4;
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, val8);
> +
> +	/* 8051 enable */
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
> +	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE);
> +
> +	/* MCU firmware download enable */
> +	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
> +	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE);
> +
> +	/* 8051 reset */
> +	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
> +	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19));
> +
> +	/* Reset firmware download checksum */
> +	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
> +	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT);
> +
> +	pages = priv->fw_size / RTL_FW_PAGE_SIZE;
> +	remainder = priv->fw_size % RTL_FW_PAGE_SIZE;
> +
> +	fwptr = priv->fw_data->data;
> +
> +	for (i = 0; i < pages; i++) {
> +		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
> +		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
> +
> +		ret = priv->fops->writeN(priv, REG_FW_START_ADDRESS,
> +					 fwptr, RTL_FW_PAGE_SIZE);
> +		if (ret != RTL_FW_PAGE_SIZE) {
> +			ret = -EAGAIN;
> +			goto fw_abort;
> +		}
> +
> +		fwptr += RTL_FW_PAGE_SIZE;
> +	}
> +
> +	if (remainder) {
> +		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
> +		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
> +		ret = priv->fops->writeN(priv, REG_FW_START_ADDRESS,
> +					 fwptr, remainder);
> +		if (ret != remainder) {
> +			ret = -EAGAIN;
> +			goto fw_abort;
> +		}
> +	}
> +
> +	ret = 0;
> +fw_abort:
> +	/* MCU firmware download disable */
> +	val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL);
> +	rtl8xxxu_write16(priv, REG_MCU_FW_DL,
> +			 val16 & (~MCU_FW_DL_ENABLE & 0xff));
> +
> +	return ret;
> +}
> +
> +static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	const struct firmware *fw;
> +	int ret = 0;
> +	u16 signature;
> +
> +	dev_info(dev, "%s: Loading firmware %s\n", DRIVER_NAME, fw_name);
> +	if (request_firmware(&fw, fw_name, &priv->udev->dev)) {
> +		dev_warn(dev, "request_firmware(%s) failed\n", fw_name);
> +		ret = -EAGAIN;
> +		goto exit;
> +	}
> +	if (!fw) {
> +		dev_warn(dev, "Firmware data not available\n");
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL);
> +	priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header);
> +
> +	signature = le16_to_cpu(priv->fw_data->signature);
> +	switch (signature & 0xfff0) {
> +	case 0x92c0:
> +	case 0x88c0:
> +	case 0x2300:
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		dev_warn(dev, "%s: Invalid firmware signature: 0x%04x\n",
> +			 __func__, signature);
> +	}
> +
> +	dev_info(dev, "Firmware revision %i.%i (signature 0x%04x)\n",
> +		 le16_to_cpu(priv->fw_data->major_version),
> +		 priv->fw_data->minor_version, signature);
> +
> +exit:
> +	release_firmware(fw);
> +	return ret;
> +}
> +
> +static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv)
> +{
> +	char *fw_name;
> +	int ret;
> +
> +	switch (priv->chip_cut) {
> +	case 0:
> +		fw_name = "rtlwifi/rtl8723aufw_A.bin";
> +		break;
> +	case 1:
> +		if (priv->enable_bluetooth)
> +			fw_name = "rtlwifi/rtl8723aufw_B.bin";
> +		else
> +			fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
> +
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = rtl8xxxu_load_firmware(priv, fw_name);
> +	return ret;
> +}
> +
> +static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv)
> +{
> +	char *fw_name;
> +	int ret;
> +
> +	if (!priv->vendor_umc)
> +		fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
> +	else if (priv->chip_cut || priv->rtlchip == 0x8192c)
> +		fw_name = "rtlwifi/rtl8192cufw_B.bin";
> +	else
> +		fw_name = "rtlwifi/rtl8192cufw_A.bin";
> +
> +	ret = rtl8xxxu_load_firmware(priv, fw_name);
> +
> +	return ret;
> +}
> +
> +static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv)
> +{
> +	u16 val16;
> +	int i = 100;
> +
> +	/* Inform 8051 to perform reset */
> +	rtl8xxxu_write8(priv, REG_HMTFR + 3, 0x20);
> +
> +	for (i = 100; i > 0; i--) {
> +		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
> +
> +		if (!(val16 & SYS_FUNC_CPU_ENABLE)) {
> +			dev_dbg(&priv->udev->dev,
> +				"%s: Firmware self reset success!\n", __func__);
> +			break;
> +		}
> +		udelay(50);
> +	}
> +
> +	if (!i) {
> +		/* Force firmware reset */
> +		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
> +		val16 &= ~SYS_FUNC_CPU_ENABLE;
> +		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
> +	}
> +}
> +
> +static int
> +rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array)
> +{
> +	int i, ret;
> +	u16 reg;
> +	u8 val;
> +
> +	for (i = 0; ; i++) {
> +		reg = array[i].reg;
> +		val = array[i].val;
> +
> +		if (reg == 0xffff && val == 0xff)
> +			break;
> +
> +		ret = rtl8xxxu_write8(priv, reg, val);
> +		if (ret != 1) {
> +			dev_warn(&priv->udev->dev,
> +				 "Failed to initialize MAC\n");
> +			return -EAGAIN;
> +		}
> +	}
> +
> +	rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a);
> +
> +	return 0;
> +}
> +
> +static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
> +				  struct rtl8xxxu_reg32val *array)
> +{
> +	int i, ret;
> +	u16 reg;
> +	u32 val;
> +
> +	for (i = 0; ; i++) {
> +		reg = array[i].reg;
> +		val = array[i].val;
> +
> +		if (reg == 0xffff && val == 0xffffffff)
> +			break;
> +
> +		ret = rtl8xxxu_write32(priv, reg, val);
> +		if (ret != sizeof(val)) {
> +			dev_warn(&priv->udev->dev,
> +				 "Failed to initialize PHY\n");
> +			return -EAGAIN;
> +		}
> +		udelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Most of this is black magic retrieved from the old rtl8723au driver
> + */
> +static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8, ldoa15, ldov12d, lpldo, ldohci12;
> +	u32 val32;
> +
> +	/*
> +	 * Todo: The vendor driver maintains a table of PHY register
> +	 *       addresses, which is initialized here. Do we need this?
> +	 */
> +
> +	val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
> +	udelay(2);
> +	val8 |= AFE_PLL_320_ENABLE;
> +	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
> +	udelay(2);
> +
> +	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff);
> +	udelay(2);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
> +	val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
> +
> +	/* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */
> +	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
> +	val32 &= ~AFE_XTAL_RF_GATE;
> +	if (priv->has_bluetooth)
> +		val32 &= ~AFE_XTAL_BT_GATE;
> +	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
> +
> +	/* 6. 0x1f[7:0] = 0x07 */
> +	val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
> +	rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
> +
> +	if (priv->hi_pa)
> +		rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table);
> +	else if (priv->tx_paths == 2)
> +		rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table);
> +	else
> +		rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table);
> +
> +
> +	if (priv->rtlchip == 0x8188c && priv->hi_pa &&
> +	    priv->vendor_umc && priv->chip_cut == 1)
> +		rtl8xxxu_write8(priv, REG_OFDM0_AGC_PARM1 + 2, 0x50);
> +
> +	if (priv->tx_paths == 1 && priv->rx_paths == 2) {
> +		/*
> +		 * For 1T2R boards, patch the registers.
> +		 *
> +		 * It looks like 8191/2 1T2R boards use path B for TX
> +		 */
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO);
> +		val32 &= ~(BIT(0) | BIT(1));
> +		val32 |= BIT(1);
> +		rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO);
> +		val32 &= ~0x300033;
> +		val32 |= 0x200022;
> +		rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
> +		val32 &= 0xff000000;
> +		val32 |= 0x45000000;
> +		rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
> +		val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK);
> +		val32 |= (OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B |
> +			  OFDM_RF_PATH_TX_B);
> +		rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGC_PARM1);
> +		val32 &= ~(BIT(4) | BIT(5));
> +		val32 |= BIT(4);
> +		rtl8xxxu_write32(priv, REG_OFDM0_AGC_PARM1, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_RFON);
> +		val32 &= ~(BIT(27) | BIT(26));
> +		val32 |= BIT(27);
> +		rtl8xxxu_write32(priv, REG_TX_CCK_RFON, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_BBON);
> +		val32 &= ~(BIT(27) | BIT(26));
> +		val32 |= BIT(27);
> +		rtl8xxxu_write32(priv, REG_TX_CCK_BBON, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_RFON);
> +		val32 &= ~(BIT(27) | BIT(26));
> +		val32 |= BIT(27);
> +		rtl8xxxu_write32(priv, REG_TX_OFDM_RFON, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_BBON);
> +		val32 &= ~(BIT(27) | BIT(26));
> +		val32 |= BIT(27);
> +		rtl8xxxu_write32(priv, REG_TX_OFDM_BBON, val32);
> +
> +		val32 = rtl8xxxu_read32(priv, REG_TX_TO_TX);
> +		val32 &= ~(BIT(27) | BIT(26));
> +		val32 |= BIT(27);
> +		rtl8xxxu_write32(priv, REG_TX_TO_TX, val32);
> +	}
> +
> +	if (priv->hi_pa)
> +		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table);
> +	else
> +		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table);
> +
> +	if (priv->rtlchip == 0x8723a &&
> +	    priv->efuse_wifi.efuse8723.version >= 0x01) {
> +		val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);
> +
> +		val8 = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
> +		val32 &= 0xff000fff;
> +		val32 |= ((val8 | (val8 << 6)) << 12);
> +
> +		rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);
> +	}
> +
> +	ldoa15 = LDOA15_ENABLE | LDOA15_OBUF;
> +	ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT);
> +	ldohci12 = 0x57;
> +	lpldo = 1;
> +	val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15;
> +
> +	rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32);
> +
> +	return 0;
> +}
> +
> +static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv,
> +				 struct rtl8xxxu_rfregval *array,
> +				 enum rtl8xxxu_rfpath path)
> +{
> +	int i, ret;
> +	u8 reg;
> +	u32 val;
> +
> +	for (i = 0; ; i++) {
> +		reg = array[i].reg;
> +		val = array[i].val;
> +
> +		if (reg == 0xff && val == 0xffffffff)
> +			break;
> +
> +		switch (reg) {
> +		case 0xfe:
> +			msleep(50);
> +			continue;
> +		case 0xfd:
> +			mdelay(5);
> +			continue;
> +		case 0xfc:
> +			mdelay(1);
> +			continue;
> +		case 0xfb:
> +			udelay(50);
> +			continue;
> +		case 0xfa:
> +			udelay(5);
> +			continue;
> +		case 0xf9:
> +			udelay(1);
> +			continue;
> +		}
> +
> +		reg &= 0x3f;
> +
> +		ret = rtl8xxxu_write_rfreg(priv, path, reg, val);
> +		if (ret) {
> +			dev_warn(&priv->udev->dev,
> +				 "Failed to initialize RF\n");
> +			return -EAGAIN;
> +		}
> +		udelay(1);
> +	}
> +
> +	return 0;
> +}
> +
> +static int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv,
> +				struct rtl8xxxu_rfregval *table,
> +				enum rtl8xxxu_rfpath path)
> +{
> +	u32 val32;
> +	u16 val16, rfsi_rfenv;
> +	u16 reg_sw_ctrl, reg_int_oe, reg_hssi_parm2;
> +
> +	switch (path) {
> +	case RF_A:
> +		reg_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL;
> +		reg_int_oe = REG_FPGA0_XA_RF_INT_OE;
> +		reg_hssi_parm2 = REG_FPGA0_XA_HSSI_PARM2;
> +		break;
> +	case RF_B:
> +		reg_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL;
> +		reg_int_oe = REG_FPGA0_XB_RF_INT_OE;
> +		reg_hssi_parm2 = REG_FPGA0_XB_HSSI_PARM2;
> +		break;
> +	default:
> +		dev_err(&priv->udev->dev, "%s:Unsupported RF path %c\n",
> +			__func__, path + 'A');
> +		return -EINVAL;
> +	}
> +	/* For path B, use XB */
> +	rfsi_rfenv = rtl8xxxu_read16(priv, reg_sw_ctrl);
> +	rfsi_rfenv &= FPGA0_RF_RFENV;
> +
> +	/*
> +	 * These two we might be able to optimize into one
> +	 */
> +	val32 = rtl8xxxu_read32(priv, reg_int_oe);
> +	val32 |= BIT(20);	/* 0x10 << 16 */
> +	rtl8xxxu_write32(priv, reg_int_oe, val32);
> +	udelay(1);
> +
> +	val32 = rtl8xxxu_read32(priv, reg_int_oe);
> +	val32 |= BIT(4);
> +	rtl8xxxu_write32(priv, reg_int_oe, val32);
> +	udelay(1);
> +
> +	/*
> +	 * These two we might be able to optimize into one
> +	 */
> +	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
> +	val32 &= ~FPGA0_HSSI_3WIRE_ADDR_LEN;
> +	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
> +	udelay(1);
> +
> +	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
> +	val32 &= ~FPGA0_HSSI_3WIRE_DATA_LEN;
> +	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
> +	udelay(1);
> +
> +	rtl8xxxu_init_rf_regs(priv, table, path);
> +
> +	/* For path B, use XB */
> +	val16 = rtl8xxxu_read16(priv, reg_sw_ctrl);
> +	val16 &= ~FPGA0_RF_RFENV;
> +	val16 |= rfsi_rfenv;
> +	rtl8xxxu_write16(priv, reg_sw_ctrl, val16);
> +
> +	return 0;
> +}
> +
> +static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data)
> +{
> +	int ret = -EBUSY;
> +	int count = 0;
> +	u32 value;
> +
> +	value = LLT_OP_WRITE | address << 8 | data;
> +
> +	rtl8xxxu_write32(priv, REG_LLT_INIT, value);
> +
> +	do {
> +		value = rtl8xxxu_read32(priv, REG_LLT_INIT);
> +		if ((value & LLT_OP_MASK) == LLT_OP_INACTIVE) {
> +			ret = 0;
> +			break;
> +		}
> +	} while (count++ < 20);
> +
> +	return ret;
> +}
> +
> +static int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page)
> +{
> +	int ret;
> +	int i;
> +
> +	for (i = 0; i < last_tx_page; i++) {
> +		ret = rtl8xxxu_llt_write(priv, i, i + 1);
> +		if (ret)
> +			goto exit;
> +	}
> +
> +	ret = rtl8xxxu_llt_write(priv, last_tx_page, 0xff);
> +	if (ret)
> +		goto exit;
> +
> +	/* Mark remaining pages as a ring buffer */
> +	for (i = last_tx_page + 1; i < 0xff; i++) {
> +		ret = rtl8xxxu_llt_write(priv, i, (i + 1));
> +		if (ret)
> +			goto exit;
> +	}
> +
> +	/*  Let last entry point to the start entry of ring buffer */
> +	ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1);
> +	if (ret)
> +		goto exit;
> +
> +exit:
> +	return ret;
> +}
> +
> +static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv)
> +{
> +	u16 val16, hi, lo;
> +	u16 hiq, mgq, bkq, beq, viq, voq;
> +	int hip, mgp, bkp, bep, vip, vop;
> +	int ret = 0;
> +
> +	switch (priv->ep_tx_count) {
> +	case 1:
> +		if (priv->ep_tx_high_queue) {
> +			hi = TRXDMA_QUEUE_HIGH;
> +		} else if (priv->ep_tx_low_queue) {
> +			hi = TRXDMA_QUEUE_LOW;
> +		} else if (priv->ep_tx_normal_queue) {
> +			hi = TRXDMA_QUEUE_NORMAL;
> +		} else {
> +			hi = 0;
> +			ret = -EINVAL;
> +		}
> +
> +		hiq = hi;
> +		mgq = hi;
> +		bkq = hi;
> +		beq = hi;
> +		viq = hi;
> +		voq = hi;
> +
> +		hip = 0;
> +		mgp = 0;
> +		bkp = 0;
> +		bep = 0;
> +		vip = 0;
> +		vop = 0;
> +		break;
> +	case 2:
> +		if (priv->ep_tx_high_queue && priv->ep_tx_low_queue) {
> +			hi = TRXDMA_QUEUE_HIGH;
> +			lo = TRXDMA_QUEUE_LOW;
> +		} else if (priv->ep_tx_normal_queue && priv->ep_tx_low_queue) {
> +			hi = TRXDMA_QUEUE_NORMAL;
> +			lo = TRXDMA_QUEUE_LOW;
> +		} else if (priv->ep_tx_high_queue && priv->ep_tx_normal_queue) {
> +			hi = TRXDMA_QUEUE_HIGH;
> +			lo = TRXDMA_QUEUE_NORMAL;
> +		} else {
> +			ret = -EINVAL;
> +			hi = 0;
> +			lo = 0;
> +		}
> +
> +		hiq = hi;
> +		mgq = hi;
> +		bkq = lo;
> +		beq = lo;
> +		viq = hi;
> +		voq = hi;
> +
> +		hip = 0;
> +		mgp = 0;
> +		bkp = 1;
> +		bep = 1;
> +		vip = 0;
> +		vop = 0;
> +		break;
> +	case 3:
> +		beq = TRXDMA_QUEUE_LOW;
> +		bkq = TRXDMA_QUEUE_LOW;
> +		viq = TRXDMA_QUEUE_NORMAL;
> +		voq = TRXDMA_QUEUE_HIGH;
> +		mgq = TRXDMA_QUEUE_HIGH;
> +		hiq = TRXDMA_QUEUE_HIGH;
> +
> +		hip = hiq ^ 3;
> +		mgp = mgq ^ 3;
> +		bkp = bkq ^ 3;
> +		bep = beq ^ 3;
> +		vip = viq ^ 3;
> +		vop = viq ^ 3;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	/*
> +	 * None of the vendor drivers are configuring the beacon
> +	 * queue here .... why?
> +	 */
> +	if (!ret) {
> +		val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL);
> +		val16 &= 0x7;
> +		val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) |
> +			(viq << TRXDMA_CTRL_VIQ_SHIFT) |
> +			(beq << TRXDMA_CTRL_BEQ_SHIFT) |
> +			(bkq << TRXDMA_CTRL_BKQ_SHIFT) |
> +			(mgq << TRXDMA_CTRL_MGQ_SHIFT) |
> +			(hiq << TRXDMA_CTRL_HIQ_SHIFT);
> +		rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16);
> +
> +		priv->pipe_out[TXDESC_QUEUE_VO] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[vop]);
> +		priv->pipe_out[TXDESC_QUEUE_VI] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[vip]);
> +		priv->pipe_out[TXDESC_QUEUE_BE] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[bep]);
> +		priv->pipe_out[TXDESC_QUEUE_BK] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[bkp]);
> +		priv->pipe_out[TXDESC_QUEUE_BEACON] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
> +		priv->pipe_out[TXDESC_QUEUE_MGNT] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[mgp]);
> +		priv->pipe_out[TXDESC_QUEUE_HIGH] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[hip]);
> +		priv->pipe_out[TXDESC_QUEUE_CMD] =
> +			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
> +	}
> +
> +	return ret;
> +}
> +
> +static void rtl8xxxu_fill_iqk_matrix_a(struct rtl8xxxu_priv *priv,
> +				       bool iqk_ok, int result[][8],
> +				       int candidate, bool tx_only)
> +{
> +	u32 oldval, x, tx0_a, reg;
> +	int y, tx0_c;
> +	u32 val32;
> +
> +	if (!iqk_ok)
> +		return;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
> +	oldval = val32 >> 22;
> +
> +	x = result[candidate][0];
> +	if ((x & 0x00000200) != 0)
> +		x = x | 0xfffffc00;
> +	tx0_a = (x * oldval) >> 8;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
> +	val32 &= ~0x3ff;
> +	val32 |= tx0_a;
> +	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
> +	val32 &= ~BIT(31);
> +	if ((x * oldval >> 7) & 0x1)
> +		val32 |= BIT(31);
> +	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
> +
> +	y = result[candidate][1];
> +	if ((y & 0x00000200) != 0)
> +		y = y | 0xfffffc00;
> +	tx0_c = (y * oldval) >> 8;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XC_TX_AFE);
> +	val32 &= ~0xf0000000;
> +	val32 |= (((tx0_c & 0x3c0) >> 6) << 28);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XC_TX_AFE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
> +	val32 &= ~0x003f0000;
> +	val32 |= ((tx0_c & 0x3f) << 16);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
> +	val32 &= ~BIT(29);
> +	if ((y * oldval >> 7) & 0x1)
> +		val32 |= BIT(29);
> +	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
> +
> +	if (tx_only) {
> +		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
> +		return;
> +	}
> +
> +	reg = result[candidate][2];
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
> +	val32 &= ~0x3ff;
> +	val32 |= (reg & 0x3ff);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
> +
> +	reg = result[candidate][3] & 0x3F;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
> +	val32 &= ~0xfc00;
> +	val32 |= ((reg << 10) & 0xfc00);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
> +
> +	reg = (result[candidate][3] >> 6) & 0xF;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_RX_IQ_EXT_ANTA);
> +	val32 &= ~0xf0000000;
> +	val32 |= (reg << 28);
> +	rtl8xxxu_write32(priv, REG_OFDM0_RX_IQ_EXT_ANTA, val32);
> +}
> +
> +static void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv,
> +				       bool iqk_ok, int result[][8],
> +				       int candidate, bool tx_only)
> +{
> +	u32 oldval, x, tx1_a, reg;
> +	int y, tx1_c;
> +	u32 val32;
> +
> +	if (!iqk_ok)
> +		return;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
> +	oldval = val32 >> 22;
> +
> +	x = result[candidate][4];
> +	if ((x & 0x00000200) != 0)
> +		x = x | 0xfffffc00;
> +	tx1_a = (x * oldval) >> 8;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
> +	val32 &= ~0x3ff;
> +	val32 |= tx1_a;
> +	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
> +	val32 &= ~BIT(27);
> +	if ((x * oldval >> 7) & 0x1)
> +		val32 |= BIT(27);
> +	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
> +
> +	y = result[candidate][5];
> +	if ((y & 0x00000200) != 0)
> +		y = y | 0xfffffc00;
> +	tx1_c = (y * oldval) >> 8;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XD_TX_AFE);
> +	val32 &= ~0xf0000000;
> +	val32 |= (((tx1_c & 0x3c0) >> 6) << 28);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XD_TX_AFE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
> +	val32 &= ~0x003f0000;
> +	val32 |= ((tx1_c & 0x3f) << 16);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
> +	val32 &= ~BIT(25);
> +	if ((y * oldval >> 7) & 0x1)
> +		val32 |= BIT(25);
> +	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
> +
> +	if (tx_only) {
> +		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
> +		return;
> +	}
> +
> +	reg = result[candidate][6];
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
> +	val32 &= ~0x3ff;
> +	val32 |= (reg & 0x3ff);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
> +
> +	reg = result[candidate][7] & 0x3f;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
> +	val32 &= ~0xfc00;
> +	val32 |= ((reg << 10) & 0xfc00);
> +	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
> +
> +	reg = (result[candidate][7] >> 6) & 0xf;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE);
> +	val32 &= ~0x0000f000;
> +	val32 |= (reg << 12);
> +	rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32);
> +}
> +
> +#define MAX_TOLERANCE		5
> +
> +static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv,
> +					int result[][8], int c1, int c2)
> +{
> +	u32 i, j, diff, simubitmap, bound = 0;
> +	int candidate[2] = {-1, -1};	/* for path A and path B */
> +	bool retval = true;
> +
> +	if (priv->tx_paths > 1)
> +		bound = 8;
> +	else
> +		bound = 4;
> +
> +	simubitmap = 0;
> +
> +	for (i = 0; i < bound; i++) {
> +		diff = (result[c1][i] > result[c2][i]) ?
> +			(result[c1][i] - result[c2][i]) :
> +			(result[c2][i] - result[c1][i]);
> +		if (diff > MAX_TOLERANCE) {
> +			if ((i == 2 || i == 6) && !simubitmap) {
> +				if (result[c1][i] + result[c1][i + 1] == 0)
> +					candidate[(i / 4)] = c2;
> +				else if (result[c2][i] + result[c2][i + 1] == 0)
> +					candidate[(i / 4)] = c1;
> +				else
> +					simubitmap = simubitmap | (1 << i);
> +			} else {
> +				simubitmap = simubitmap | (1 << i);
> +			}
> +		}
> +	}
> +
> +	if (simubitmap == 0) {
> +		for (i = 0; i < (bound / 4); i++) {
> +			if (candidate[i] >= 0) {
> +				for (j = i * 4; j < (i + 1) * 4 - 2; j++)
> +					result[3][j] = result[candidate[i]][j];
> +				retval = false;
> +			}
> +		}
> +		return retval;
> +	} else if (!(simubitmap & 0x0f)) {
> +		/* path A OK */
> +		for (i = 0; i < 4; i++)
> +			result[3][i] = result[c1][i];
> +	} else if (!(simubitmap & 0xf0) && priv->tx_paths > 1) {
> +		/* path B OK */
> +		for (i = 4; i < 8; i++)
> +			result[3][i] = result[c1][i];
> +	}
> +
> +	return false;
> +}
> +
> +static void
> +rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv, const u32 *reg, u32 *backup)
> +{
> +	int i;
> +
> +	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
> +		backup[i] = rtl8xxxu_read8(priv, reg[i]);
> +
> +	backup[i] = rtl8xxxu_read32(priv, reg[i]);
> +}
> +
> +static void rtl8xxxu_restore_mac_regs(struct rtl8xxxu_priv *priv,
> +				      const u32 *reg, u32 *backup)
> +{
> +	int i;
> +
> +	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
> +		rtl8xxxu_write8(priv, reg[i], backup[i]);
> +
> +	rtl8xxxu_write32(priv, reg[i], backup[i]);
> +}
> +
> +static void rtl8xxxu_save_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
> +			       u32 *backup, int count)
> +{
> +	int i;
> +
> +	for (i = 0; i < count; i++)
> +		backup[i] = rtl8xxxu_read32(priv, regs[i]);
> +}
> +
> +static void rtl8xxxu_restore_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
> +				  u32 *backup, int count)
> +{
> +	int i;
> +
> +	for (i = 0; i < count; i++)
> +		rtl8xxxu_write32(priv, regs[i], backup[i]);
> +}
> +
> +
> +static void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs,
> +				  bool path_a_on)
> +{
> +	u32 path_on;
> +	int i;
> +
> +	path_on = path_a_on ? 0x04db25a4 : 0x0b1b25a4;
> +	if (priv->tx_paths == 1) {
> +		path_on = 0x0bdb25a0;
> +		rtl8xxxu_write32(priv, regs[0], 0x0b1b25a0);
> +	} else {
> +		rtl8xxxu_write32(priv, regs[0], path_on);
> +	}
> +
> +	for (i = 1 ; i < RTL8XXXU_ADDA_REGS ; i++)
> +		rtl8xxxu_write32(priv, regs[i], path_on);
> +}
> +
> +static void rtl8xxxu_mac_calibration(struct rtl8xxxu_priv *priv,
> +				     const u32 *regs, u32 *backup)
> +{
> +	int i = 0;
> +
> +	rtl8xxxu_write8(priv, regs[i], 0x3f);
> +
> +	for (i = 1 ; i < (RTL8XXXU_MAC_REGS - 1); i++)
> +		rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(3)));
> +
> +	rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(5)));
> +}
> +
> +static int rtl8xxxu_iqk_path_a(struct rtl8xxxu_priv *priv)
> +{
> +	u32 reg_eac, reg_e94, reg_e9c, reg_ea4, val32;
> +	int result = 0;
> +
> +	/* path-A IQK setting */
> +	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1f);
> +	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1f);
> +	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82140102);
> +
> +	val32 = (priv->rf_paths > 1) ? 0x28160202 :
> +		/*IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202: */
> +		0x28160502;
> +	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, val32);
> +
> +	/* path-B IQK setting */
> +	if (priv->rf_paths > 1) {
> +		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x10008c22);
> +		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x10008c22);
> +		rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82140102);
> +		rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28160202);
> +	}
> +
> +	/* LO calibration setting */
> +	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x001028d1);
> +
> +	/* One shot, path A LOK & IQK */
> +	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
> +	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
> +
> +	mdelay(1);
> +
> +	/* Check failed */
> +	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
> +	reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
> +	reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
> +	reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2);
> +
> +	if (!(reg_eac & BIT(28)) &&
> +	    ((reg_e94 & 0x03ff0000) != 0x01420000) &&
> +	    ((reg_e9c & 0x03ff0000) != 0x00420000))
> +		result |= 0x01;
> +	else	/* If TX not OK, ignore RX */
> +		goto out;
> +
> +	/* If TX is OK, check whether RX is OK */
> +	if (!(reg_eac & BIT(27)) &&
> +	    ((reg_ea4 & 0x03ff0000) != 0x01320000) &&
> +	    ((reg_eac & 0x03ff0000) != 0x00360000))
> +		result |= 0x02;
> +	else
> +		dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n",
> +			 __func__);
> +out:
> +	return result;
> +}
> +
> +static int rtl8xxxu_iqk_path_b(struct rtl8xxxu_priv *priv)
> +{
> +	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
> +	int result = 0;
> +
> +	/* One shot, path B LOK & IQK */
> +	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002);
> +	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000);
> +
> +	mdelay(1);
> +
> +	/* Check failed */
> +	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
> +	reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
> +	reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
> +	reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
> +	reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
> +
> +	if (!(reg_eac & BIT(31)) &&
> +	    ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
> +	    ((reg_ebc & 0x03ff0000) != 0x00420000))
> +		result |= 0x01;
> +	else
> +		goto out;
> +
> +	if (!(reg_eac & BIT(30)) &&
> +	    (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) &&
> +	    (((reg_ecc & 0x03ff0000) >> 16) != 0x36))
> +		result |= 0x02;
> +	else
> +		dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n",
> +			 __func__);
> +out:
> +	return result;
> +}
> +
> +static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
> +				     int result[][8], int t)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	u32 i, val32;
> +	int path_a_ok, path_b_ok;
> +	int retry = 2;
> +	const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
> +		REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
> +		REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
> +		REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
> +		REG_TX_OFDM_BBON, REG_TX_TO_RX,
> +		REG_TX_TO_TX, REG_RX_CCK,
> +		REG_RX_OFDM, REG_RX_WAIT_RIFS,
> +		REG_RX_TO_RX, REG_STANDBY,
> +		REG_SLEEP, REG_PMPD_ANAEN
> +	};
> +	const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
> +		REG_TXPAUSE, REG_BEACON_CTRL,
> +		REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
> +	};
> +	const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
> +		REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
> +		REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
> +		REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
> +		REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE
> +	};
> +
> +	/*
> +	 * Note: IQ calibration must be performed after loading
> +	 *       PHY_REG.txt , and radio_a, radio_b.txt
> +	 */
> +
> +	if (t == 0) {
> +		/* Save ADDA parameters, turn Path A ADDA on */
> +		rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
> +				   RTL8XXXU_ADDA_REGS);
> +		rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
> +		rtl8xxxu_save_regs(priv, iqk_bb_regs,
> +				   priv->bb_backup, RTL8XXXU_BB_REGS);
> +	}
> +
> +	rtl8xxxu_path_adda_on(priv, adda_regs, true);
> +
> +	if (t == 0) {
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
> +		if (val32 & FPGA0_HSSI_PARM1_PI)
> +			priv->pi_enabled = 1;
> +	}
> +
> +	if (!priv->pi_enabled) {
> +		/* Switch BB to PI mode to do IQ Calibration. */
> +		rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
> +		rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
> +	}
> +
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +	val32 &= ~FPGA_RF_MODE_CCK;
> +	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +
> +	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
> +	rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
> +	rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
> +	val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
> +	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
> +
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
> +	val32 &= ~BIT(10);
> +	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
> +	val32 &= ~BIT(10);
> +	rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
> +
> +	if (priv->tx_paths > 1) {
> +		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
> +		rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000);
> +	}
> +
> +	/* MAC settings */
> +	rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
> +
> +	/* Page B init */
> +	rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000);
> +
> +	if (priv->tx_paths > 1)
> +		rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000);
> +
> +	/* IQ calibration setting */
> +	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
> +	rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
> +	rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
> +
> +	for (i = 0; i < retry; i++) {
> +		path_a_ok = rtl8xxxu_iqk_path_a(priv);
> +		if (path_a_ok == 0x03) {
> +			val32 = rtl8xxxu_read32(priv,
> +						REG_TX_POWER_BEFORE_IQK_A);
> +			result[t][0] = (val32 >> 16) & 0x3ff;
> +			val32 = rtl8xxxu_read32(priv,
> +						REG_TX_POWER_AFTER_IQK_A);
> +			result[t][1] = (val32 >> 16) & 0x3ff;
> +			val32 = rtl8xxxu_read32(priv,
> +						REG_RX_POWER_BEFORE_IQK_A_2);
> +			result[t][2] = (val32 >> 16) & 0x3ff;
> +			val32 = rtl8xxxu_read32(priv,
> +						REG_RX_POWER_AFTER_IQK_A_2);
> +			result[t][3] = (val32 >> 16) & 0x3ff;
> +			break;
> +		} else if (i == (retry - 1) && path_a_ok == 0x01) {
> +			/* TX IQK OK */
> +			dev_dbg(dev, "%s: Path A IQK Only Tx Success!!\n",
> +				__func__);
> +
> +			val32 = rtl8xxxu_read32(priv,
> +						REG_TX_POWER_BEFORE_IQK_A);
> +			result[t][0] = (val32 >> 16) & 0x3ff;
> +			val32 = rtl8xxxu_read32(priv,
> +						REG_TX_POWER_AFTER_IQK_A);
> +			result[t][1] = (val32 >> 16) & 0x3ff;
> +		}
> +	}
> +
> +	if (!path_a_ok)
> +		dev_dbg(dev, "%s: Path A IQK failed!\n", __func__);
> +
> +	if (priv->tx_paths > 1) {
> +		/*
> +		 * Path A into standby
> +		 */
> +		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x0);
> +		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
> +		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
> +
> +		/* Turn Path B ADDA on */
> +		rtl8xxxu_path_adda_on(priv, adda_regs, false);
> +
> +		for (i = 0; i < retry; i++) {
> +			path_b_ok = rtl8xxxu_iqk_path_b(priv);
> +			if (path_b_ok == 0x03) {
> +				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
> +				result[t][4] = (val32 >> 16) & 0x3ff;
> +				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
> +				result[t][5] = (val32 >> 16) & 0x3ff;
> +				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
> +				result[t][6] = (val32 >> 16) & 0x3ff;
> +				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
> +				result[t][7] = (val32 >> 16) & 0x3ff;
> +				break;
> +			} else if (i == (retry - 1) && path_b_ok == 0x01) {
> +				/* TX IQK OK */
> +				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
> +				result[t][4] = (val32 >> 16) & 0x3ff;
> +				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
> +				result[t][5] = (val32 >> 16) & 0x3ff;
> +			}
> +		}
> +
> +		if (!path_b_ok)
> +			dev_dbg(dev, "%s: Path B IQK failed!\n", __func__);
> +	}
> +
> +	/* Back to BB mode, load original value */
> +	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0);
> +
> +	if (t) {
> +		if (!priv->pi_enabled) {
> +			/*
> +			 * Switch back BB to SI mode after finishing
> +			 * IQ Calibration
> +			 */
> +			val32 = 0x01000000;
> +			rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, val32);
> +			rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, val32);
> +		}
> +
> +		/* Reload ADDA power saving parameters */
> +		rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup,
> +				      RTL8XXXU_ADDA_REGS);
> +
> +		/* Reload MAC parameters */
> +		rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
> +
> +		/* Reload BB parameters */
> +		rtl8xxxu_restore_regs(priv, iqk_bb_regs,
> +				      priv->bb_backup, RTL8XXXU_BB_REGS);
> +
> +		/* Restore RX initial gain */
> +		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3);
> +
> +		if (priv->tx_paths > 1) {
> +			rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM,
> +					 0x00032ed3);
> +		}
> +
> +		/* Load 0xe30 IQC default value */
> +		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00);
> +		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00);
> +	}
> +}
> +
> +static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
> +{
> +	struct device *dev = &priv->udev->dev;
> +	int result[4][8];	/* last is final result */
> +	int i, candidate;
> +	bool path_a_ok, path_b_ok;
> +	u32 reg_e94, reg_e9c, reg_ea4, reg_eac;
> +	u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc;
> +	s32 reg_tmp = 0;
> +	bool simu;
> +
> +	memset(result, 0, sizeof(result));
> +	candidate = -1;
> +
> +	path_a_ok = false;
> +	path_b_ok = false;
> +
> +	rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +
> +	for (i = 0; i < 3; i++) {
> +		rtl8xxxu_phy_iqcalibrate(priv, result, i);
> +
> +		if (i == 1) {
> +			simu = rtl8xxxu_simularity_compare(priv, result, 0, 1);
> +			if (simu) {
> +				candidate = 0;
> +				break;
> +			}
> +		}
> +
> +		if (i == 2) {
> +			simu = rtl8xxxu_simularity_compare(priv, result, 0, 2);
> +			if (simu) {
> +				candidate = 0;
> +				break;
> +			}
> +
> +			simu = rtl8xxxu_simularity_compare(priv, result, 1, 2);
> +			if (simu) {
> +				candidate = 1;
> +			} else {
> +				for (i = 0; i < 8; i++)
> +					reg_tmp += result[3][i];
> +
> +				if (reg_tmp)
> +					candidate = 3;
> +				else
> +					candidate = -1;
> +			}
> +		}
> +	}
> +
> +	for (i = 0; i < 4; i++) {
> +		reg_e94 = result[i][0];
> +		reg_e9c = result[i][1];
> +		reg_ea4 = result[i][2];
> +		reg_eac = result[i][3];
> +		reg_eb4 = result[i][4];
> +		reg_ebc = result[i][5];
> +		reg_ec4 = result[i][6];
> +		reg_ecc = result[i][7];
> +	}
> +
> +	if (candidate >= 0) {
> +		reg_e94 = result[candidate][0];
> +		priv->rege94 =  reg_e94;
> +		reg_e9c = result[candidate][1];
> +		priv->rege9c = reg_e9c;
> +		reg_ea4 = result[candidate][2];
> +		reg_eac = result[candidate][3];
> +		reg_eb4 = result[candidate][4];
> +		priv->regeb4 = reg_eb4;
> +		reg_ebc = result[candidate][5];
> +		priv->regebc = reg_ebc;
> +		reg_ec4 = result[candidate][6];
> +		reg_ecc = result[candidate][7];
> +		dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate);
> +		dev_dbg(dev,
> +			"%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x "
> +			"ecc=%x\n ", __func__, reg_e94, reg_e9c,
> +			reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc);
> +		path_a_ok = true;
> +		path_b_ok = true;
> +	} else {
> +		reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100;
> +		reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0;
> +	}
> +
> +	if (reg_e94 && candidate >= 0)
> +		rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result,
> +					   candidate, (reg_ea4 == 0));
> +
> +	if (priv->tx_paths > 1 && reg_eb4)
> +		rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
> +					   candidate, (reg_ec4 == 0));
> +
> +	rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
> +			   priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
> +}
> +
> +static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
> +{
> +	u32 val32;
> +	u32 rf_amode, rf_bmode = 0, lstf;
> +
> +	/* Check continuous TX and Packet TX */
> +	lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
> +
> +	if (lstf & OFDM_LSTF_MASK) {
> +		/* Disable all continuous TX */
> +		val32 = lstf & ~OFDM_LSTF_MASK;
> +		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
> +
> +		/* Read original RF mode Path A */
> +		rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC);

The compiler on the PPC system (V4.6.3) is not as good at determining if a 
variable has been set as is V4.8.3. It generates the warning "warning: 
‘rf_amode’ may be used uninitialized in this function [-Wuninitialized]" for the 
above statement. As I hate to initialize any variable that does not need it, 
this one should probably be left alone; however, you may wish to add a comment.

> +
> +		/* Set RF mode to standby Path A */
> +		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC,
> +				     (rf_amode & 0x8ffff) | 0x10000);
> +
> +		/* Path-B */
> +		if (priv->tx_paths > 1) {
> +			rf_bmode = rtl8xxxu_read_rfreg(priv, RF_B,
> +						       RF6052_REG_AC);
> +
> +			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
> +					     (rf_bmode & 0x8ffff) | 0x10000);
> +		}
> +	} else {
> +		/*  Deal with Packet TX case */
> +		/*  block all queues */
> +		rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
> +	}
> +
> +	/* Start LC calibration */
> +	val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG);
> +	val32 |= 0x08000;
> +	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32);
> +
> +	msleep(100);
> +
> +	/* Restore original parameters */
> +	if (lstf & OFDM_LSTF_MASK) {
> +		/* Path-A */
> +		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, lstf);
> +		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, rf_amode);
> +
> +		/* Path-B */
> +		if (priv->tx_paths > 1)
> +			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
> +					     rf_bmode);
> +	} else /*  Deal with Packet TX case */
> +		rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
> +}
> +
> +static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv)
> +{
> +	int i;
> +	u16 reg;
> +
> +	reg = REG_MACID;
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]);
> +
> +	return 0;
> +}
> +
> +static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid)
> +{
> +	int i;
> +	u16 reg;
> +
> +	dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid);
> +
> +	reg = REG_BSSID;
> +
> +	for (i = 0; i < ETH_ALEN; i++)
> +		rtl8xxxu_write8(priv, reg + i, bssid[i]);
> +
> +	return 0;
> +}
> +
> +static void
> +rtl8xxxu_set_ampdu_factor(struct rtl8xxxu_priv *priv, u8 ampdu_factor)
> +{
> +	u8 vals[4] = { 0x41, 0xa8, 0x72, 0xb9 };
> +	u8 max_agg = 0xf;
> +	int i;
> +
> +	ampdu_factor = 1 << (ampdu_factor + 2);
> +	if (ampdu_factor > max_agg)
> +		ampdu_factor = max_agg;
> +
> +	for (i = 0; i < 4; i++) {
> +		if ((vals[i] & 0xf0) > (ampdu_factor << 4))
> +			vals[i] = (vals[i] & 0x0f) | (ampdu_factor << 4);
> +
> +		if ((vals[i] & 0x0f) > ampdu_factor)
> +			vals[i] = (vals[i] & 0xf0) | ampdu_factor;
> +
> +		rtl8xxxu_write8(priv, REG_AGGLEN_LMT + i, vals[i]);
> +	}
> +}
> +
> +static void rtl8xxxu_set_ampdu_min_space(struct rtl8xxxu_priv *priv, u8 density)
> +{
> +	u8 val8;
> +
> +	val8 = rtl8xxxu_read8(priv, REG_AMPDU_MIN_SPACE);
> +	val8 &= 0xf8;
> +	val8 |= density;
> +	rtl8xxxu_write8(priv, REG_AMPDU_MIN_SPACE, val8);
> +}
> +
> +static int rtl8xxxu_active_to_emu(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	int count, ret;
> +
> +	/* Start of rtl8723AU_card_enable_flow */
> +	/* Act to Cardemu sequence*/
> +	/* Turn off RF */
> +	rtl8xxxu_write8(priv, REG_RF_CTRL, 0);
> +
> +	/* 0x004E[7] = 0, switch DPDT_SEL_P output from register 0x0065[2] */
> +	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
> +	val8 &= ~LEDCFG2_DPDT_SELECT;
> +	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
> +
> +	/* 0x0005[1] = 1 turn off MAC by HW state machine*/
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 |= BIT(1);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
> +		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +		if ((val8 & BIT(1)) == 0)
> +			break;
> +		udelay(10);
> +	}
> +
> +	if (!count) {
> +		dev_warn(&priv->udev->dev, "%s: Disabling MAC timed out\n",
> +			 __func__);
> +		ret = -EBUSY;
> +		goto exit;
> +	}
> +
> +	/* 0x0000[5] = 1 analog Ips to digital, 1:isolation */
> +	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
> +	val8 |= SYS_ISO_ANALOG_IPS;
> +	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
> +
> +	/* 0x0020[0] = 0 disable LDOA12 MACRO block*/
> +	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
> +	val8 &= ~LDOA15_ENABLE;
> +	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
> +
> +exit:
> +	return ret;
> +}
> +
> +static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	u8 val32;
> +	int count, ret;
> +
> +	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
> +
> +	/*
> +	 * Poll - wait for RX packet to complete
> +	 */
> +	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
> +		val32 = rtl8xxxu_read32(priv, 0x5f8);
> +		if (!val32)
> +			break;
> +		udelay(10);
> +	}
> +
> +	if (!count) {
> +		dev_warn(&priv->udev->dev,
> +			 "%s: RX poll timed out (0x05f8)\n", __func__);
> +		ret = -EBUSY;
> +		goto exit;
> +	}
> +
> +	/* Disable CCK and OFDM, clock gated */
> +	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
> +	val8 &= ~SYS_FUNC_BBRSTB;
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
> +
> +	udelay(2);
> +
> +	/* Reset baseband */
> +	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
> +	val8 &= ~SYS_FUNC_BB_GLB_RSTN;
> +	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
> +
> +	/* Reset MAC TRX */
> +	val8 = rtl8xxxu_read8(priv, REG_CR);
> +	val8 = CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE;
> +	rtl8xxxu_write8(priv, REG_CR, val8);
> +
> +	/* Reset MAC TRX */
> +	val8 = rtl8xxxu_read8(priv, REG_CR + 1);
> +	val8 &= ~BIT(1); /* CR_SECURITY_ENABLE */
> +	rtl8xxxu_write8(priv, REG_CR + 1, val8);
> +
> +	/* Respond TX OK to scheduler */
> +	val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST);
> +	val8 |= DUAL_TSF_TX_OK;
> +	rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8);
> +
> +exit:
> +	return ret;
> +}
> +
> +static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +
> +	/* Clear suspend enable and power down enable*/
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 &= ~(BIT(3) | BIT(7));
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	/* 0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/
> +	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
> +	val8 &= ~BIT(0);
> +	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
> +
> +	/* 0x04[12:11] = 11 enable WL suspend*/
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 &= ~(BIT(3) | BIT(4));
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +}
> +
> +static int rtl8xxxu_emu_to_active(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	u32 val32;
> +	int count, ret = 0;
> +
> +	/* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/
> +	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
> +	val8 |= LDOA15_ENABLE;
> +	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
> +
> +	/* 0x67[0] = 0 to disable BT_GPS_SEL pins*/
> +	val8 = rtl8xxxu_read8(priv, 0x0067);
> +	val8 &= ~BIT(4);
> +	rtl8xxxu_write8(priv, 0x0067, val8);
> +
> +	mdelay(1);
> +
> +	/* 0x00[5] = 0 release analog Ips to digital, 1:isolation */
> +	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
> +	val8 &= ~SYS_ISO_ANALOG_IPS;
> +	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
> +
> +	/* disable SW LPS 0x04[10]= 0 */
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 &= ~BIT(2);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	/* wait till 0x04[17] = 1 power ready*/
> +	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
> +		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
> +		if (val32 & BIT(17))
> +			break;
> +
> +		udelay(10);
> +	}
> +
> +	if (!count) {
> +		ret = -EBUSY;
> +		goto exit;
> +	}
> +
> +	/* We should be able to optimize the following three entries into one */
> +
> +	/* release WLON reset 0x04[16]= 1*/
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
> +	val8 |= BIT(0);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
> +
> +	/* disable HWPDN 0x04[15]= 0*/
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 &= ~BIT(7);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	/* disable WL suspend*/
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 &= ~(BIT(3) | BIT(4));
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	/* set, then poll until 0 */
> +	val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
> +	val32 |= APS_FSMCO_MAC_ENABLE;
> +	rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
> +
> +	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
> +		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
> +		if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
> +			ret = 0;
> +			break;
> +		}
> +		udelay(10);
> +	}
> +
> +	if (!count) {
> +		ret = -EBUSY;
> +		goto exit;
> +	}
> +
> +	/* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */
> +	/*
> +	 * Note: Vendor driver actually clears this bit, despite the
> +	 * documentation claims it's being set!
> +	 */
> +	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
> +	val8 |= LEDCFG2_DPDT_SELECT;
> +	val8 &= ~LEDCFG2_DPDT_SELECT;
> +	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
> +
> +exit:
> +	return ret;
> +}
> +
> +static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +
> +	/* 0x0007[7:0] = 0x20 SOP option to disable BG/MB */
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x20);
> +
> +	/* 0x04[12:11] = 01 enable WL suspend */
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 &= ~BIT(4);
> +	val8 |= BIT(3);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
> +	val8 |= BIT(7);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
> +
> +	/* 0x48[16] = 1 to enable GPIO9 as EXT wakeup */
> +	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
> +	val8 |= BIT(0);
> +	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
> +
> +	return 0;
> +}
> +
> +static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	u16 val16;
> +	u32 val32;
> +	int ret;
> +
> +	/*
> +	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
> +	 */
> +	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
> +
> +	rtl8xxxu_disabled_to_emu(priv);
> +
> +	ret = rtl8xxxu_emu_to_active(priv);
> +	if (ret)
> +		goto exit;
> +
> +	/*
> +	 * 0x0004[19] = 1, reset 8051
> +	 */
> +	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
> +	val8 |= BIT(3);
> +	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
> +
> +	/*
> +	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
> +	 * Set CR bit10 to enable 32k calibration.
> +	 */
> +	val16 = rtl8xxxu_read16(priv, REG_CR);
> +	val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
> +		  CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
> +		  CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
> +		  CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE |
> +		  CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
> +	rtl8xxxu_write16(priv, REG_CR, val16);
> +
> +	/* For EFuse PG */
> +	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
> +	val32 &= ~(BIT(28) | BIT(29) | BIT(30));
> +	val32 |= (0x06 << 28);
> +	rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32);
> +exit:
> +	return ret;
> +}
> +
> +static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	u16 val16;
> +	u32 val32;
> +	int i;
> +
> +	for (i = 100; i; i--) {
> +		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO);
> +		if (val8 & APS_FSMCO_PFM_ALDN)
> +			break;
> +	}
> +
> +	if (!i) {
> +		pr_info("%s: Poll failed\n", __func__);
> +		return -ENODEV;
> +	}
> +
> +	/*
> +	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
> +	 */
> +	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
> +	rtl8xxxu_write8(priv, REG_SPS0_CTRL, 0x2b);
> +	udelay(100);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_LDOV12D_CTRL);
> +	if (!(val8 & LDOV12D_ENABLE)) {
> +		pr_info("%s: Enabling LDOV12D (%02x)\n", __func__, val8);
> +		val8 |= LDOV12D_ENABLE;
> +		rtl8xxxu_write8(priv, REG_LDOV12D_CTRL, val8);
> +
> +		udelay(100);
> +
> +		val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
> +		val8 &= ~SYS_ISO_MD2PP;
> +		rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
> +	}
> +
> +	/*
> +	 * Auto enable WLAN
> +	 */
> +	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
> +	val16 |= APS_FSMCO_MAC_ENABLE;
> +	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
> +
> +	for (i = 1000; i; i--) {
> +		val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
> +		if (!(val16 & APS_FSMCO_MAC_ENABLE))
> +			break;
> +	}
> +	if (!i) {
> +		pr_info("%s: FSMCO_MAC_ENABLE poll failed\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	/*
> +	 * Enable radio, GPIO, LED
> +	 */
> +	val16 = APS_FSMCO_HW_SUSPEND | APS_FSMCO_ENABLE_POWERDOWN |
> +		APS_FSMCO_PFM_ALDN;
> +	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
> +
> +	/*
> +	 * Release RF digital isolation
> +	 */
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
> +	val16 &= ~SYS_ISO_DIOR;
> +	rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
> +	val8 &= ~APSD_CTRL_OFF;
> +	rtl8xxxu_write8(priv, REG_APSD_CTRL, val8);
> +	for (i = 200; i; i--) {
> +		val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
> +		if (!(val8 & APSD_CTRL_OFF_STATUS))
> +			break;
> +	}
> +
> +	if (!i) {
> +		pr_info("%s: APSD_CTRL poll failed\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	/*
> +	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
> +	 */
> +	val16 = rtl8xxxu_read16(priv, REG_CR);
> +	val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
> +		CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | CR_PROTOCOL_ENABLE |
> +		CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE;
> +	rtl8xxxu_write16(priv, REG_CR, val16);
> +
> +	/*
> +	 * Workaround for 8188RU LNA power leakage problem.
> +	 */
> +	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
> +		val32 &= ~BIT(1);
> +		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
> +	}
> +	return 0;
> +}
> +
> +static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv)
> +{
> +	u8 val8;
> +	u16 val16;
> +	u32 val32;
> +
> +	/*
> +	 * Workaround for 8188RU LNA power leakage problem.
> +	 */
> +	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
> +		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
> +		val32 |= BIT(1);
> +		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
> +	}
> +
> +	rtl8xxxu_active_to_lps(priv);
> +
> +	/* Turn off RF */
> +	rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00);
> +
> +	/* Reset Firmware if running in RAM */
> +	if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL)
> +		rtl8xxxu_firmware_self_reset(priv);
> +
> +	/* Reset MCU */
> +	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
> +	val16 &= ~SYS_FUNC_CPU_ENABLE;
> +	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
> +
> +	/* Reset MCU ready status */
> +	rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
> +
> +	rtl8xxxu_active_to_emu(priv);
> +	rtl8xxxu_emu_to_disabled(priv);
> +
> +	/* Reset MCU IO Wrapper */
> +	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
> +	val8 &= ~BIT(0);
> +	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
> +	val8 |= BIT(0);
> +	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
> +
> +	/* RSV_CTRL 0x1C[7:0] = 0x0e  lock ISO/CLK/Power control register */
> +	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e);
> +}
> +
> +static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct device *dev = &priv->udev->dev;
> +	struct rtl8xxxu_rfregval *rftable;
> +	bool macpower;
> +	int ret;
> +	u8 val8;
> +	u16 val16;
> +	u32 val32;
> +
> +	/* Check if MAC is already powered on */
> +	val8 = rtl8xxxu_read8(priv, REG_CR);
> +
> +	/*
> +	 * Fix 92DU-VC S3 hang with the reason is that secondary mac is not
> +	 * initialized. First MAC returns 0xea, second MAC returns 0x00
> +	 */
> +	if (val8 == 0xea)
> +		macpower = false;
> +	else
> +		macpower = true;
> +
> +	ret = priv->fops->power_on(priv);
> +	if (ret < 0) {
> +		dev_warn(dev, "%s: Failed power on\n", __func__);
> +		goto exit;
> +	}
> +
> +	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
> +	if (!macpower) {
> +		ret = rtl8xxxu_init_llt_table(priv, TX_TOTAL_PAGE_NUM);
> +		if (ret) {
> +			dev_warn(dev, "%s: LLT table init failed\n", __func__);
> +			goto exit;
> +		}
> +	}
> +
> +	ret = rtl8xxxu_download_firmware(priv);
> +	dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret);
> +	if (ret)
> +		goto exit;
> +	ret = rtl8xxxu_start_firmware(priv);
> +	dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret);
> +	if (ret)
> +		goto exit;
> +
> +	ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table);
> +	dev_dbg(dev, "%s: init_mac %i\n", __func__, ret);
> +	if (ret)
> +		goto exit;
> +
> +	ret = rtl8xxxu_init_phy_bb(priv);
> +	dev_dbg(dev, "%s: init_phy_bb %i\n", __func__, ret);
> +	if (ret)
> +		goto exit;
> +
> +	switch(priv->rtlchip) {
> +	case 0x8723a:
> +		rftable = rtl8723au_radioa_1t_init_table;
> +		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
> +		break;
> +	case 0x8188c:
> +		if (priv->hi_pa)
> +			rftable = rtl8188ru_radioa_1t_highpa_table;
> +		else
> +			rftable = rtl8192cu_radioa_1t_init_table;
> +		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
> +		break;
> +	case 0x8191c:
> +		rftable = rtl8192cu_radioa_1t_init_table;
> +		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
> +		break;
> +	case 0x8192c:
> +		rftable = rtl8192cu_radioa_2t_init_table;
> +		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
> +		if (ret)
> +			break;
> +		rftable = rtl8192cu_radiob_2t_init_table;
> +		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	if (ret)
> +		goto exit;
> +
> +	/* Reduce 80M spur */
> +	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
> +	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
> +	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
> +	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
> +
> +	/* RFSW Control - clear bit 14 ?? */
> +	rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003);
> +	/* 0x07000760 */
> +	val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW |
> +		FPGA0_RF_ANTSWB | FPGA0_RF_PAPE |
> +		((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE) <<
> +		 FPGA0_RF_BD_CTRL_SHIFT);
> +	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
> +	/* 0x860[6:5]= 00 - why? - this sets antenna B */
> +	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66F60210);
> +
> +	priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A,
> +						  RF6052_REG_MODE_AG);
> +
> +	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
> +	if (!macpower) {
> +		if (priv->ep_tx_normal_queue)
> +			val8 = TX_PAGE_NUM_NORM_PQ;
> +		else
> +			val8 = 0;
> +
> +		rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8);
> +
> +		val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD;
> +
> +		if (priv->ep_tx_high_queue)
> +			val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT);
> +		if (priv->ep_tx_low_queue)
> +			val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT);
> +
> +		rtl8xxxu_write32(priv, REG_RQPN, val32);
> +
> +		/*
> +		 * Set TX buffer boundary
> +		 */
> +		val8 = TX_TOTAL_PAGE_NUM + 1;
> +		rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8);
> +		rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8);
> +		rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8);
> +		rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8);
> +		rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8);
> +	}
> +
> +	ret = rtl8xxxu_init_queue_priority(priv);
> +	dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret);
> +	if (ret)
> +		goto exit;
> +
> +	/*
> +	 * Set RX page boundary
> +	 */
> +	rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff);
> +	/*
> +	 * Transfer page size is always 128
> +	 */
> +	val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) |
> +		(PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT);
> +	rtl8xxxu_write8(priv, REG_PBP, val8);
> +
> +	/*
> +	 * Unit in 8 bytes, not obvious what it is used for
> +	 */
> +	rtl8xxxu_write8(priv, REG_RX_DRVINFO_SZ, 4);
> +
> +	/*
> +	 * Enable all interrupts - not obvious USB needs to do this
> +	 */
> +	rtl8xxxu_write32(priv, REG_HISR, 0xffffffff);
> +	rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
> +
> +	rtl8xxxu_set_mac(priv);
> +	rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION);
> +
> +	/*
> +	 * Configure initial WMAC settings
> +	 */
> +	val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST |
> +		/* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */
> +		RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL |
> +		RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC;
> +	rtl8xxxu_write32(priv, REG_RCR, val32);
> +
> +	/*
> +	 * Accept all multicast
> +	 */
> +	rtl8xxxu_write32(priv, REG_MAR, 0xffffffff);
> +	rtl8xxxu_write32(priv, REG_MAR + 4, 0xffffffff);
> +
> +	/*
> +	 * Init adaptive controls
> +	 */
> +	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
> +	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
> +	val32 |= RESPONSE_RATE_RRSR_CCK_ONLY_1M;
> +	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
> +
> +	/* CCK = 0x0a, OFDM = 0x10 */
> +#if 0
> +	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
> +#else
> +	rtl8xxxu_set_spec_sifs(priv, 0x10, 0x10);
> +#endif
> +	rtl8xxxu_set_retry(priv, 0x30, 0x30);
> +	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
> +
> +	/*
> +	 * Init EDCA
> +	 */
> +	rtl8xxxu_write16(priv, REG_MAC_SPEC_SIFS, 0x100a);
> +
> +	/* Set CCK SIFS */
> +	rtl8xxxu_write16(priv, REG_SIFS_CCK, 0x100a);
> +
> +	/* Set OFDM SIFS */
> +	rtl8xxxu_write16(priv, REG_SIFS_OFDM, 0x100a);
> +
> +	/* TXOP */
> +	rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, 0x005ea42b);
> +	rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, 0x0000a44f);
> +	rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, 0x005ea324);
> +	rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, 0x002fa226);
> +
> +	/* Set data auto rate fallback retry count */
> +	rtl8xxxu_write32(priv, REG_DARFRC, 0x00000000);
> +	rtl8xxxu_write32(priv, REG_DARFRC + 4, 0x10080404);
> +	rtl8xxxu_write32(priv, REG_RARFRC, 0x04030201);
> +	rtl8xxxu_write32(priv, REG_RARFRC + 4, 0x08070605);
> +
> +	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL);
> +	val8 |= FWHW_TXQ_CTRL_AMPDU_RETRY;
> +	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, val8);
> +
> +	/*  Set ACK timeout */
> +	rtl8xxxu_write8(priv, REG_ACKTO, 0x40);
> +
> +	/*
> +	 * Initialize beacon parameters
> +	 */
> +	val16 = BEACON_DISABLE_TSF_UPDATE | (BEACON_DISABLE_TSF_UPDATE << 8);
> +	rtl8xxxu_write16(priv, REG_BEACON_CTRL, val16);
> +	rtl8xxxu_write16(priv, REG_TBTT_PROHIBIT, 0x6404);
> +	rtl8xxxu_write8(priv, REG_DRIVER_EARLY_INT, DRIVER_EARLY_INT_TIME);
> +	rtl8xxxu_write8(priv, REG_BEACON_DMA_TIME, BEACON_DMA_ATIME_INT_TIME);
> +	rtl8xxxu_write16(priv, REG_BEACON_TCFG, 0x660F);
> +
> +	/*
> +	 * Enable CCK and OFDM block
> +	 */
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +	val32 |= (FPGA_RF_MODE_CCK | FPGA_RF_MODE_OFDM);
> +	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +
> +	/*
> +	 * Invalidate all CAM entries - bit 30 is undocumented
> +	 */
> +	rtl8xxxu_write32(priv, REG_CAM_CMD, CAM_CMD_POLLING | BIT(30));
> +
> +	/*
> +	 * Start out with default power levels for channel 6, 20MHz
> +	 */
> +	rtl8723a_set_tx_power(priv, 1, false);
> +
> +	/* Let the 8051 take control of antenna setting */
> +	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
> +	val8 |= LEDCFG2_DPDT_SELECT;
> +	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
> +
> +	rtl8xxxu_write8(priv, REG_HWSEQ_CTRL, 0xff);
> +
> +	/* Disable BAR - not sure if this has any effect on USB */
> +	rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff);
> +
> +	rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0);
> +
> +#if 0
> +	/*
> +	 * From 8192cu driver
> +	 */
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
> +	val32 &= ~BIT(6);
> +	val32 |= BIT(5);
> +	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
> +#endif
> +
> +	/*
> +	 * Not sure if we should get into this at all
> +	 */
> +	if (priv->iqk_initialized) {
> +		rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
> +				      priv->bb_recovery_backup,
> +				      RTL8XXXU_BB_REGS);
> +	} else {
> +		rtl8723a_phy_iq_calibrate(priv);
> +		priv->iqk_initialized = true;
> +	}
> +
> +	/*
> +	 * This should enable thermal meter
> +	 */
> +	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60);
> +
> +	rtl8723a_phy_lc_calibrate(priv);
> +
> +	/* fix USB interface interference issue */
> +	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
> +	rtl8xxxu_write8(priv, 0xfe41, 0x8d);
> +	rtl8xxxu_write8(priv, 0xfe42, 0x80);
> +	rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320);
> +
> +	/* Solve too many protocol error on USB bus */
> +	/* Can't do this for 8188/8192 UMC A cut parts */
> +	rtl8xxxu_write8(priv, 0xfe40, 0xe6);
> +	rtl8xxxu_write8(priv, 0xfe41, 0x94);
> +	rtl8xxxu_write8(priv, 0xfe42, 0x80);
> +
> +	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
> +	rtl8xxxu_write8(priv, 0xfe41, 0x19);
> +	rtl8xxxu_write8(priv, 0xfe42, 0x80);
> +
> +	rtl8xxxu_write8(priv, 0xfe40, 0xe5);
> +	rtl8xxxu_write8(priv, 0xfe41, 0x91);
> +	rtl8xxxu_write8(priv, 0xfe42, 0x80);
> +
> +	rtl8xxxu_write8(priv, 0xfe40, 0xe2);
> +	rtl8xxxu_write8(priv, 0xfe41, 0x81);
> +	rtl8xxxu_write8(priv, 0xfe42, 0x80);
> +
> +#if 0
> +	/* Init BT hw config. */
> +	rtl8723a_init_bt(priv);
> +#endif
> +
> +	/*
> +	 * Not sure if we really need to save these parameters, but the
> +	 * vendor driver does
> +	 */
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
> +	if (val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)
> +		priv->path_a_hi_power = 1;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
> +	priv->path_a_rf_paths = val32 & OFDM_RF_PATH_RX_MASK;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1);
> +	priv->path_a_ig_value = val32 & OFDM0_X_AGC_CORE1_IGI_MASK;
> +
> +	/* Set NAV_UPPER to 30000us */
> +	val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT);
> +	rtl8xxxu_write8(priv, REG_NAV_UPPER, val8);
> +
> +	/*
> +	 * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test,
> +	 * but we need to fin root cause.
> +	 */
> +	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
> +	if ((val32 & 0xff000000) != 0x83000000) {
> +		val32 |= FPGA_RF_MODE_CCK;
> +		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
> +	}
> +
> +	val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL);
> +	val32 |= FWHW_TXQ_CTRL_XMIT_MGMT_ACK;
> +	/* ack for xmit mgmt frames. */
> +	rtl8xxxu_write32(priv, REG_FWHW_TXQ_CTRL, val32);
> +
> +exit:
> +	return ret;
> +}
> +
> +static void rtl8xxxu_disable_device(struct ieee80211_hw *hw)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +
> +	rtl8xxxu_power_off(priv);
> +}
> +
> +static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv,
> +			       struct ieee80211_key_conf *key, const u8 *mac)
> +{
> +	u32 cmd, val32, addr, ctrl;
> +	int j, i, tmp_debug;
> +
> +	tmp_debug = rtl8xxxu_debug;
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_KEY)
> +		rtl8xxxu_debug |= RTL8XXXU_DEBUG_REG_WRITE;
> +
> +	addr = key->keyidx << CAM_CMD_KEY_SHIFT;
> +	ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID;
> +
> +	for (j = 5; j >= 0; j--) {
> +		switch (j) {
> +		case 0:
> +			val32 = ctrl | (mac[0] << 16) | (mac[1] << 24);
> +			break;
> +		case 1:
> +			val32 = mac[2] | (mac[3] << 8) |
> +				(mac[4] << 16) | (mac[5] << 24);
> +			break;
> +		default:
> +			i = (j - 2) << 2;
> +			val32 = key->key[i] | (key->key[i + 1] << 8) |
> +				key->key[i + 2] << 16 | key->key[i + 3] << 24;
> +			break;
> +		}
> +
> +		rtl8xxxu_write32(priv, REG_CAM_WRITE, val32);
> +		cmd = CAM_CMD_POLLING | CAM_CMD_WRITE | (addr + j);
> +		rtl8xxxu_write32(priv, REG_CAM_CMD, cmd);
> +		udelay(100);
> +	}
> +
> +	rtl8xxxu_debug = tmp_debug;
> +}
> +
> +static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
> +				   struct ieee80211_vif *vif, const u8 *mac)
> +{
> +}
> +
> +static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw,
> +				      struct ieee80211_vif *vif)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	u8 val8;
> +
> +	val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
> +	val8 &= ~BEACON_DISABLE_TSF_UPDATE;
> +	rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
> +}
> +
> +static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv,
> +				      struct ieee80211_sta *sta)
> +{
> +	struct h2c_cmd h2c;
> +	u32 ramask;
> +
> +	/* TODO: Set bits 28-31 for rate adaptive id */
> +	ramask = (sta->supp_rates[0] & 0xfff) |
> +		sta->ht_cap.mcs.rx_mask[0] << 12 |
> +		sta->ht_cap.mcs.rx_mask[1] << 20;
> +
> +	h2c.ramask.cmd = H2C_SET_RATE_MASK;
> +	h2c.ramask.mask_lo = cpu_to_le16(ramask & 0xffff);
> +	h2c.ramask.mask_hi = cpu_to_le16(ramask >> 16);
> +
> +	h2c.ramask.arg = 0x80;
> +	if (sta->ht_cap.cap &
> +	    (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))
> +		h2c.ramask.arg |= 0x20;
> +
> +	dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x\n", __func__,
> +		ramask, h2c.ramask.arg);
> +	rtl8723a_h2c_cmd(priv, &h2c);
> +}
> +
> +static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
> +{
> +	u32 val32;
> +	u8 rate_idx = 0;
> +
> +	rate_cfg &= RESPONSE_RATE_BITMAP_ALL;
> +
> +	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
> +	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
> +	val32 |= rate_cfg;
> +	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
> +
> +	dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__,	rate_cfg);
> +
> +	while (rate_cfg) {
> +		rate_cfg = (rate_cfg >> 1);
> +		rate_idx++;
> +	}
> +	rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx);
> +}
> +
> +static void
> +rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
> +			  struct ieee80211_bss_conf *bss_conf, u32 changed)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct device *dev = &priv->udev->dev;
> +	struct ieee80211_sta *sta;
> +	struct rtl8xxxu_sta_priv *sta_priv;
> +	u32 val32;
> +#if 0
> +	u16 val16;
> +#endif
> +	u8 val8;
> +
> +	if (changed & BSS_CHANGED_ASSOC) {
> +		struct h2c_cmd h2c;
> +
> +		dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc);
> +
> +		memset(&h2c, 0, sizeof(struct h2c_cmd));
> +		rtl8xxxu_set_linktype(priv, vif->type);
> +
> +		if (bss_conf->assoc) {
> +			rcu_read_lock();
> +			sta = ieee80211_find_sta(vif, bss_conf->bssid);
> +			if (!sta) {
> +				dev_info(dev, "%s: ASSOC no sta found\n",
> +					 __func__);
> +				rcu_read_unlock();
> +				goto error;
> +			}
> +
> +			if (sta->ht_cap.ht_supported)
> +				dev_info(dev, "%s: HT supported\n", __func__);
> +			if (sta->vht_cap.vht_supported)
> +				dev_info(dev, "%s: VHT supported\n", __func__);
> +			rtl8xxxu_update_rate_mask(priv, sta);
> +			rcu_read_unlock();
> +
> +			val32 = rtl8xxxu_read32(priv, REG_RCR);
> +			val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON;
> +			rtl8xxxu_write32(priv, REG_RCR, val32);
> +
> +			/* Enable RX of data frames */
> +			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
> +
> +			rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
> +
> +			rtl8723a_stop_tx_beacon(priv);
> +
> +			/* joinbss sequence */
> +			rtl8xxxu_write16(priv, REG_BCN_PSR_RPT,
> +					 0xc000 | bss_conf->aid);
> +
> +#if 0
> +			val16 = rtl8xxxu_read16(priv, REG_CR);
> +			val16 |= CR_SW_BEACON_ENABLE;
> +			rtl8xxxu_read16(priv, REG_CR, val16);
> +
> +			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
> +			val8 &= ~BEACON_FUNCTION_ENABLE;
> +			val8 |= BEACON_DISABLE_TSF_UPDATE;
> +			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
> +
> +			val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
> +			if (val8 & BIT(6))
> +				recover = true;
> +
> +			val8 &= ~BIT(6);
> +			rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
> +
> +			/* build fake beacon */
> +
> +			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
> +			val8 |= BEACON_FUNCTION_ENABLE;
> +			val8 &= ~BEACON_DISABLE_TSF_UPDATE;
> +			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
> +
> +			if (recover) {
> +				val8 = rtl8xxxu_read8(priv,
> +						      REG_FWHW_TXQ_CTRL + 2);
> +				val8 |= BIT(6);
> +				rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2,
> +						val8);
> +			}
> +			val16 = rtl8xxxu_read16(priv, REG_CR);
> +			val16 &= ~CR_SW_BEACON_ENABLE;
> +			rtl8xxxu_read16(priv, REG_CR, val16);
> +#endif
> +			h2c.joinbss.data = H2C_JOIN_BSS_CONNECT;
> +		} else {
> +			val32 = rtl8xxxu_read32(priv, REG_RCR);
> +			val32 &= ~(RCR_CHECK_BSSID_MATCH |
> +				   RCR_CHECK_BSSID_BEACON);
> +			rtl8xxxu_write32(priv, REG_RCR, val32);
> +
> +			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
> +			val8 |= BEACON_DISABLE_TSF_UPDATE;
> +			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
> +
> +			/* Disable RX of data frames */
> +			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
> +			h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT;
> +		}
> +		h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT;
> +		rtl8723a_h2c_cmd(priv, &h2c);
> +	}
> +
> +	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
> +		dev_dbg(dev, "Changed ERP_PREAMBLE: Use short preamble %i\n",
> +			bss_conf->use_short_preamble);
> +		val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
> +		if (bss_conf->use_short_preamble)
> +			val32 |= RSR_ACK_SHORT_PREAMBLE;
> +		else
> +			val32 &= ~RSR_ACK_SHORT_PREAMBLE;
> +		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
> +
> +		rcu_read_lock();
> +		sta = ieee80211_find_sta(vif, bss_conf->bssid);
> +		if (sta) {
> +			sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
> +			if (bss_conf->use_short_preamble)
> +				sta_priv->short_preamble = true;
> +			else
> +				sta_priv->short_preamble = false;
> +		}
> +		rcu_read_unlock();
> +	}
> +
> +	if (changed & BSS_CHANGED_ERP_SLOT) {
> +		dev_dbg(dev, "Changed ERP_SLOT: short_slot_time %i\n",
> +			bss_conf->use_short_slot);
> +
> +		if (bss_conf->use_short_slot)
> +			val8 = 9;
> +		else
> +			val8 = 20;
> +		rtl8xxxu_write8(priv, REG_SLOT, val8);
> +	}
> +
> +	if (changed & BSS_CHANGED_BSSID) {
> +		dev_dbg(dev, "Changed BSSID!\n");
> +		rtl8xxxu_set_bssid(priv, bss_conf->bssid);
> +	}
> +
> +	if (changed & BSS_CHANGED_BASIC_RATES) {
> +		dev_dbg(dev, "Changed BASIC_RATES!\n");
> +		rtl8xxxu_set_basic_rates(priv, bss_conf->basic_rates);
> +	}
> +error:
> +	return;
> +}
> +
> +static u32 rtl8xxxu_80211_to_rtl_queue(u32 queue)
> +{
> +	u32 rtlqueue;
> +
> +	switch (queue) {
> +	case IEEE80211_AC_VO:
> +		rtlqueue = TXDESC_QUEUE_VO;
> +		break;
> +	case IEEE80211_AC_VI:
> +		rtlqueue = TXDESC_QUEUE_VI;
> +		break;
> +	case IEEE80211_AC_BE:
> +		rtlqueue = TXDESC_QUEUE_BE;
> +		break;
> +	case IEEE80211_AC_BK:
> +		rtlqueue = TXDESC_QUEUE_BK;
> +		break;
> +	default:
> +		rtlqueue = TXDESC_QUEUE_BE;
> +	}
> +
> +	return rtlqueue;
> +}
> +
> +static u32 rtl8xxxu_queue_select(struct ieee80211_hw *hw, struct sk_buff *skb)
> +{
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +	u32 queue;
> +
> +	if (ieee80211_is_mgmt(hdr->frame_control))
> +		queue = TXDESC_QUEUE_MGNT;
> +	else
> +		queue = rtl8xxxu_80211_to_rtl_queue(skb_get_queue_mapping(skb));
> +
> +	return queue;
> +}
> +
> +static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc)
> +{
> +	__le16 *ptr = (__le16 *)tx_desc;
> +	u16 csum = 0;
> +	int i;
> +
> +	/*
> +	 * Clear csum field before calculation, as the csum field is
> +	 * in the middle of the struct.
> +	 */
> +	tx_desc->csum = cpu_to_le16(0);
> +
> +	for (i = 0; i < (sizeof(struct rtl8xxxu_tx_desc) / sizeof(u16)); i++)
> +		csum = csum ^ le16_to_cpu(ptr[i]);
> +
> +	tx_desc->csum |= cpu_to_le16(csum);
> +}
> +
> +static void rtl8xxxu_tx_complete(struct urb *urb)
> +{
> +	struct sk_buff *skb = (struct sk_buff *)urb->context;
> +	struct ieee80211_tx_info *tx_info;
> +	struct ieee80211_hw *hw;
> +
> +	tx_info = IEEE80211_SKB_CB(skb);
> +	hw = tx_info->rate_driver_data[0];
> +
> +	skb_pull(skb, sizeof(struct rtl8xxxu_tx_desc));
> +
> +	ieee80211_tx_info_clear_status(tx_info);
> +	tx_info->status.rates[0].idx = -1;
> +	tx_info->status.rates[0].count = 0;
> +
> +#if 0
> +	/*
> +	 * Until we figure out how to obtain the info,
> +	 * do not fool the stack.
> +	 */
> +	tx_info->flags |= IEEE80211_TX_STAT_ACK;
> +#endif
> +
> +	ieee80211_tx_status_irqsafe(hw, skb);
> +
> +	usb_free_urb(urb);
> +}
> +
> +static void rtl8xxxu_dump_action(struct device *dev,
> +				 struct ieee80211_hdr *hdr)
> +{
> +	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
> +	u16 cap, timeout;
> +
> +	if (!(rtl8xxxu_debug & RTL8XXXU_DEBUG_ACTION))
> +		return;
> +
> +	switch (mgmt->u.action.u.addba_resp.action_code) {
> +	case WLAN_ACTION_ADDBA_RESP:
> +		cap = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
> +		timeout = le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
> +		dev_info(dev, "WLAN_ACTION_ADDBA_RESP: "
> +			 "timeout %i, tid %02x, buf_size %02x, policy %02x, "
> +			 "status %02x\n",
> +			 timeout,
> +			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
> +			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
> +			 (cap >> 1) & 0x1,
> +			 le16_to_cpu(mgmt->u.action.u.addba_resp.status));
> +		break;
> +	case WLAN_ACTION_ADDBA_REQ:
> +		cap = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
> +		timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
> +		dev_info(dev, "WLAN_ACTION_ADDBA_REQ: "
> +			 "timeout %i, tid %02x, buf_size %02x, policy %02x\n",
> +			 timeout,
> +			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
> +			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
> +			 (cap >> 1) & 0x1);
> +		break;
> +	default:
> +		dev_info(dev, "action frame %02x\n",
> +			 mgmt->u.action.u.addba_resp.action_code);
> +		break;
> +	}
> +}
> +
> +static void rtl8xxxu_tx(struct ieee80211_hw *hw,
> +			struct ieee80211_tx_control *control,
> +			struct sk_buff *skb)
> +{
> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
> +	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
> +	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct rtl8xxxu_tx_desc *tx_desc;
> +	struct ieee80211_sta *sta = NULL;
> +	struct rtl8xxxu_sta_priv *sta_priv = NULL;
> +	struct device *dev = &priv->udev->dev;
> +	struct urb *urb;
> +	u32 queue, rate;
> +	u16 pktlen = skb->len;
> +	u16 seq_number;
> +	u16 rate_flag = tx_info->control.rates[0].flags;
> +	int ret;
> +
> +	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
> +		dev_warn(dev,
> +			 "%s: Not enough headroom (%i) for tx descriptor\n",
> +			 __func__, skb_headroom(skb));
> +		goto error;
> +	}
> +
> +	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
> +		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
> +			 __func__, skb->len);
> +		goto error;
> +	}
> +
> +	urb = usb_alloc_urb(0, GFP_KERNEL);

The above statement generated a "scheduling while atomic" splat. The gfp_t 
argument needs to be GFP_KERNEL.

> +	if (!urb) {
> +		dev_warn(dev, "%s: Unable to allocate urb\n", __func__);
> +		goto error;
> +	}
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX)
> +		dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n",
> +			 __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen);
> +
> +	if (ieee80211_is_action(hdr->frame_control))
> +		rtl8xxxu_dump_action(dev, hdr);
> +
> +	tx_info->rate_driver_data[0] = hw;
> +
> +	if (control && control->sta) {
> +		sta = control->sta;
> +		sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
> +	}
> +
> +	tx_desc = (struct rtl8xxxu_tx_desc *)
> +		skb_push(skb, sizeof(struct rtl8xxxu_tx_desc));
> +
> +	memset(tx_desc, 0, sizeof(struct rtl8xxxu_tx_desc));
> +	tx_desc->pkt_size = cpu_to_le16(pktlen);
> +	tx_desc->pkt_offset = sizeof(struct rtl8xxxu_tx_desc);
> +
> +	tx_desc->txdw0 =
> +		TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT;
> +	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
> +	    is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
> +		tx_desc->txdw0 |= TXDESC_BROADMULTICAST;
> +
> +	queue = rtl8xxxu_queue_select(hw, skb);
> +	tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT);
> +
> +	if (tx_info->control.hw_key) {
> +		switch (tx_info->control.hw_key->cipher) {
> +		case WLAN_CIPHER_SUITE_WEP40:
> +		case WLAN_CIPHER_SUITE_WEP104:
> +		case WLAN_CIPHER_SUITE_TKIP:
> +			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_RC4);
> +			break;
> +		case WLAN_CIPHER_SUITE_CCMP:
> +			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_AES);
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
> +	tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT);
> +
> +	if (rate_flag & IEEE80211_TX_RC_MCS)
> +		rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0;
> +	else
> +		rate = tx_rate->hw_value;
> +	tx_desc->txdw5 = cpu_to_le32(rate);
> +
> +	if (ieee80211_is_data(hdr->frame_control))
> +		tx_desc->txdw5 |= cpu_to_le32(0x0001ff00);
> +
> +	/* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */
> +	if (ieee80211_is_data_qos(hdr->frame_control) && sta) {
> +		if (sta->ht_cap.ht_supported) {
> +			u32 ampdu, val32;
> +
> +			ampdu = (u32)sta->ht_cap.ampdu_density;
> +			val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;
> +			tx_desc->txdw2 |= cpu_to_le32(val32);
> +			tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE);
> +		} else
> +			tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
> +	} else
> +		tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
> +
> +	if (ieee80211_is_data_qos(hdr->frame_control))
> +		tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS);
> +	if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ||
> +	    (sta_priv && sta_priv->short_preamble))
> +		tx_desc->txdw4 |= cpu_to_le32(TXDESC_SHORT_PREAMBLE);
> +	if (rate_flag & IEEE80211_TX_RC_SHORT_GI ||
> +	    (ieee80211_is_data_qos(hdr->frame_control) &&
> +	     sta && sta->ht_cap.cap &
> +	     (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) {
> +		tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI);
> +	}
> +	if (ieee80211_is_mgmt(hdr->frame_control)) {
> +		tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value);
> +		tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE);
> +		tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT);
> +		tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE);
> +	}
> +
> +	if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
> +		/* Use RTS rate 24M - does the mac80211 tell us which to use? */
> +		tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M);
> +		tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE);
> +		tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE);
> +	}
> +
> +	rtl8xxxu_calc_tx_desc_csum(tx_desc);
> +
> +	usb_fill_bulk_urb(urb, priv->udev, priv->pipe_out[queue], skb->data,
> +			  skb->len, rtl8xxxu_tx_complete, skb);
> +
> +	usb_anchor_urb(urb, &priv->tx_anchor);
> +	ret = usb_submit_urb(urb, GFP_KERNEL);

Again, this needs to use GFP_ATOMIC.

> +	if (ret) {
> +		usb_unanchor_urb(urb);
> +		goto error;
> +	}
> +	return;
> +error:
> +	dev_kfree_skb(skb);
> +}
> +
> +static void rtl8xxxu_rx_complete(struct urb *urb)
> +{
> +	struct rtl8xxxu_rx_urb *rx_urb =
> +		container_of(urb, struct rtl8xxxu_rx_urb, urb);
> +	struct ieee80211_hw *hw = rx_urb->hw;
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct sk_buff *skb = (struct sk_buff *)urb->context;
> +	struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data;
> +	struct rtl8723au_phy_stats *phy_stats;
> +	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
> +	struct ieee80211_mgmt *mgmt;
> +	struct device *dev = &priv->udev->dev;
> +	__le32 *_rx_desc_le = (__le32 *)skb->data;
> +	u32 *_rx_desc = (u32 *)skb->data;
> +	int cnt, len, drvinfo_sz, desc_shift, i, ret;
> +
> +	for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++)
> +		_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
> +
> +	cnt = rx_desc->frag;
> +	len = rx_desc->pktlen;
> +	drvinfo_sz = rx_desc->drvinfo_sz * 8;
> +	desc_shift = rx_desc->shift;
> +	skb_put(skb, urb->actual_length);
> +
> +	if (urb->status == 0) {
> +		skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc));
> +		phy_stats = (struct rtl8723au_phy_stats *)skb->data;
> +
> +		skb_pull(skb, drvinfo_sz + desc_shift);
> +
> +		mgmt = (struct ieee80211_mgmt *)skb->data;
> +
> +		memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
> +
> +		/*
> +		 * Note this is valid for CCK rates only - FIXME
> +		 */
> +		if (rx_desc->phy_stats) {
> +			u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
> +
> +			switch (cck_agc_rpt & 0xc0) {
> +			case 0xc0:
> +				rx_status->signal = -46 - (cck_agc_rpt & 0x3e);
> +				break;
> +			case 0x80:
> +				rx_status->signal = -26 - (cck_agc_rpt & 0x3e);
> +				break;
> +			case 0x40:
> +				rx_status->signal = -12 - (cck_agc_rpt & 0x3e);
> +				break;
> +			case 0x00:
> +				rx_status->signal = 16 - (cck_agc_rpt & 0x3e);
> +				break;
> +			}
> +		}
> +
> +		rx_status->freq = hw->conf.chandef.chan->center_freq;
> +		rx_status->band = hw->conf.chandef.chan->band;
> +
> +		rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
> +
> +		if (!rx_desc->swdec)
> +			rx_status->flag |= RX_FLAG_DECRYPTED;
> +		if (rx_desc->crc32)
> +			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
> +		if (rx_desc->bw)
> +			rx_status->flag |= RX_FLAG_40MHZ;
> +
> +		if (rx_desc->rxht) {
> +			rx_status->flag |= RX_FLAG_HT;
> +			rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
> +		} else {
> +			rx_status->rate_idx = rx_desc->rxmcs;
> +		}
> +
> +		ieee80211_rx_irqsafe(hw, skb);
> +		skb = NULL;
> +		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
> +		if (ret) {
> +			dev_warn(dev, "%s: Unable to allocate skb\n", __func__);
> +			goto cleanup;
> +		}
> +	} else {
> +		dev_dbg(dev, "%s: status %i\n",	__func__, urb->status);
> +		goto cleanup;
> +	}
> +	return;
> +
> +cleanup:
> +	usb_free_urb(urb);
> +	dev_kfree_skb(skb);
> +	return;
> +}
> +
> +static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
> +				  struct rtl8xxxu_rx_urb *rx_urb)
> +{
> +	struct sk_buff *skb;
> +	int skb_size;
> +	int ret;
> +
> +	skb_size = sizeof(struct rtl8xxxu_rx_desc) + RTL_RX_BUFFER_SIZE;
> +	skb = dev_alloc_skb(skb_size);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	memset(skb->data, 0, sizeof(struct rtl8xxxu_rx_desc));
> +	usb_fill_bulk_urb(&rx_urb->urb, priv->udev, priv->pipe_in, skb->data,
> +			  skb_size, rtl8xxxu_rx_complete, skb);
> +	usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor);
> +	ret = usb_submit_urb(&rx_urb->urb, GFP_ATOMIC);
> +	if (ret)
> +		usb_unanchor_urb(&rx_urb->urb);
> +	return ret;
> +}
> +
> +static void rtl8xxxu_int_complete(struct urb *urb)
> +{
> +	struct rtl8xxxu_priv *priv = (struct rtl8xxxu_priv *)urb->context;
> +	struct device *dev = &priv->udev->dev;
> +	int ret;
> +
> +	dev_dbg(dev, "%s: status %i\n", __func__, urb->status);
> +	if (urb->status == 0) {
> +		usb_anchor_urb(urb, &priv->int_anchor);
> +		ret = usb_submit_urb(urb, GFP_ATOMIC);
> +		if (ret)
> +			usb_unanchor_urb(urb);
> +	} else {
> +		dev_info(dev, "%s: Error %i\n", __func__, urb->status);
> +	}
> +}
> +
> +
> +static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct urb *urb;
> +	u32 val32;
> +	int ret;
> +
> +	urb = usb_alloc_urb(0, GFP_KERNEL);
> +	if (!urb)
> +		return -ENOMEM;
> +
> +	usb_fill_int_urb(urb, priv->udev, priv->pipe_interrupt,
> +			 priv->int_buf, USB_INTR_CONTENT_LENGTH,
> +			 rtl8xxxu_int_complete, priv, 1);
> +	usb_anchor_urb(urb, &priv->int_anchor);
> +	ret = usb_submit_urb(urb, GFP_KERNEL);
> +	if (ret) {
> +		usb_unanchor_urb(urb);
> +		goto error;
> +	}
> +
> +	val32 = rtl8xxxu_read32(priv, REG_USB_HIMR);
> +	val32 |= USB_HIMR_CPWM;
> +	rtl8xxxu_write32(priv, REG_USB_HIMR, val32);
> +
> +error:
> +	return ret;
> +}
> +
> +static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
> +				  struct ieee80211_vif *vif)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	int ret;
> +	u8 val8;
> +
> +	switch (vif->type) {
> +	case NL80211_IFTYPE_STATION:
> +		rtl8723a_stop_tx_beacon(priv);
> +
> +		val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
> +		val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE |
> +			BEACON_DISABLE_TSF_UPDATE;
> +		rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
> +		ret = 0;
> +		break;
> +	default:
> +		ret = -EOPNOTSUPP;
> +	}
> +
> +	rtl8xxxu_set_linktype(priv, vif->type);
> +
> +	return ret;
> +}
> +
> +static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw,
> +				      struct ieee80211_vif *vif)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +
> +	dev_dbg(&priv->udev->dev, "%s\n", __func__);
> +}
> +
> +static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct device *dev = &priv->udev->dev;
> +	u16 val16;
> +	int ret = 0, channel;
> +	bool ht40;
> +
> +	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
> +		dev_info(dev,
> +			 "%s: channel: %i (changed %08x chandef.width %02x)\n",
> +			 __func__, hw->conf.chandef.chan->hw_value,
> +			 changed, hw->conf.chandef.width);
> +
> +	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
> +		val16 = ((hw->conf.long_frame_max_tx_count <<
> +			  RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) |
> +			((hw->conf.short_frame_max_tx_count <<
> +			  RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK);
> +		rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
> +	}
> +
> +	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
> +		switch (hw->conf.chandef.width) {
> +		case NL80211_CHAN_WIDTH_20_NOHT:
> +		case NL80211_CHAN_WIDTH_20:
> +			ht40 = false;
> +			break;
> +		case NL80211_CHAN_WIDTH_40:
> +			ht40 = true;
> +			break;
> +		default:
> +			ret = -ENOTSUPP;
> +			goto exit;
> +		}
> +
> +		channel = hw->conf.chandef.chan->hw_value;
> +
> +		rtl8723a_set_tx_power(priv, channel, ht40);
> +
> +		rtl8723au_config_channel(hw);
> +	}
> +
> +exit:
> +	return ret;
> +}
> +
> +static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw,
> +			    struct ieee80211_vif *vif, u16 queue,
> +			    const struct ieee80211_tx_queue_params *param)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct device *dev = &priv->udev->dev;
> +	u32 val32;
> +	u8 aifs, acm_ctrl, acm_bit;
> +
> +	aifs = param->aifs;
> +
> +	val32 = aifs |
> +		fls(param->cw_min) << EDCA_PARAM_ECW_MIN_SHIFT |
> +		fls(param->cw_max) << EDCA_PARAM_ECW_MAX_SHIFT |
> +		(u32)param->txop << EDCA_PARAM_TXOP_SHIFT;
> +
> +	acm_ctrl = rtl8xxxu_read8(priv, REG_ACM_HW_CTRL);
> +	dev_dbg(dev,
> +		"%s: IEEE80211 queue %02x val %08x, acm %i, acm_ctrl %02x\n",
> +		__func__, queue, val32, param->acm, acm_ctrl);
> +
> +	switch (queue) {
> +	case IEEE80211_AC_VO:
> +		acm_bit = ACM_HW_CTRL_VO;
> +		rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, val32);
> +		break;
> +	case IEEE80211_AC_VI:
> +		acm_bit = ACM_HW_CTRL_VI;
> +		rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, val32);
> +		break;
> +	case IEEE80211_AC_BE:
> +		acm_bit = ACM_HW_CTRL_BE;
> +		rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, val32);
> +		break;
> +	case IEEE80211_AC_BK:
> +		acm_bit = ACM_HW_CTRL_BK;
> +		rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, val32);
> +		break;
> +	default:
> +		acm_bit = 0;
> +		break;
> +	}
> +
> +	if (param->acm)
> +		acm_ctrl |= acm_bit;
> +	else
> +		acm_ctrl &= ~acm_bit;
> +	rtl8xxxu_write8(priv, REG_ACM_HW_CTRL, acm_ctrl);
> +
> +	return 0;
> +}
> +
> +static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw,
> +				      unsigned int changed_flags,
> +				      unsigned int *total_flags, u64 multicast)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +
> +	dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n",
> +		__func__, changed_flags, *total_flags);
> +
> +	*total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC);
> +}
> +
> +static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts)
> +{
> +	if (rts > 2347)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
> +			    struct ieee80211_vif *vif,
> +			    struct ieee80211_sta *sta,
> +			    struct ieee80211_key_conf *key)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct device *dev = &priv->udev->dev;
> +	u8 mac_addr[ETH_ALEN];
> +	u8 val8;
> +	u16 val16;
> +	u32 val32;
> +	int retval = -EOPNOTSUPP;
> +
> +	dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n",
> +		__func__, cmd, key->cipher, key->keyidx);
> +
> +	if (vif->type != NL80211_IFTYPE_STATION)
> +		return -EOPNOTSUPP;
> +
> +	if (key->keyidx > 3)
> +		return -EOPNOTSUPP;
> +
> +	switch (key->cipher) {
> +	case WLAN_CIPHER_SUITE_WEP40:
> +	case WLAN_CIPHER_SUITE_WEP104:
> +
> +		break;
> +	case WLAN_CIPHER_SUITE_CCMP:
> +		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
> +		break;
> +	case WLAN_CIPHER_SUITE_TKIP:
> +		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
> +		dev_dbg(dev, "%s: pairwise key\n", __func__);
> +		ether_addr_copy(mac_addr, sta->addr);
> +	} else {
> +		dev_dbg(dev, "%s: group key\n", __func__);
> +		eth_broadcast_addr(mac_addr);
> +	}
> +
> +	val16 = rtl8xxxu_read16(priv, REG_CR);
> +	val16 |= CR_SECURITY_ENABLE;
> +	rtl8xxxu_write16(priv, REG_CR, val16);
> +
> +	val8 = SEC_CFG_TX_SEC_ENABLE | SEC_CFG_TXBC_USE_DEFKEY |
> +		SEC_CFG_RX_SEC_ENABLE | SEC_CFG_RXBC_USE_DEFKEY;
> +	val8 |= SEC_CFG_TX_USE_DEFKEY | SEC_CFG_RX_USE_DEFKEY;
> +	rtl8xxxu_write8(priv, REG_SECURITY_CFG, val8);
> +
> +	switch (cmd) {
> +	case SET_KEY:
> +		/*
> +		 * This is a bit of a hack - the lower bits of the cipher
> +		 * suite selector happens to match the cipher index in the
> +		 * CAM
> +		 */
> +		key->hw_key_idx = key->keyidx;
> +		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
> +		rtl8xxxu_cam_write(priv, key, mac_addr);
> +		retval = 0;
> +		break;
> +	case DISABLE_KEY:
> +		rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000);
> +		val32 = CAM_CMD_POLLING | CAM_CMD_WRITE |
> +			key->keyidx << CAM_CMD_KEY_SHIFT;
> +		rtl8xxxu_write32(priv, REG_CAM_CMD, val32);
> +		retval = 0;
> +		break;
> +	default:
> +		dev_warn(dev, "%s: Unsupported command %02x\n", __func__, cmd);
> +	}
> +
> +	return retval;
> +}
> +
> +static int
> +rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
> +		      enum ieee80211_ampdu_mlme_action action,
> +		      struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct device *dev = &priv->udev->dev;
> +	u8 ampdu_factor, ampdu_density;
> +
> +	switch (action) {
> +	case IEEE80211_AMPDU_TX_START:
> +		dev_info(dev, "%s: IEEE80211_AMPDU_TX_START\n", __func__);
> +		ampdu_factor = sta->ht_cap.ampdu_factor;
> +		ampdu_density = sta->ht_cap.ampdu_density;
> +		rtl8xxxu_set_ampdu_factor(priv, ampdu_factor);
> +		rtl8xxxu_set_ampdu_min_space(priv, ampdu_density);
> +		dev_dbg(dev,
> +			"Changed HT: ampdu_factor %02x, ampdu_density %02x\n",
> +			ampdu_factor, ampdu_density);
> +		break;
> +	case IEEE80211_AMPDU_TX_STOP_FLUSH:
> +		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);
> +		rtl8xxxu_set_ampdu_factor(priv, 0);
> +		rtl8xxxu_set_ampdu_min_space(priv, 0);
> +		break;
> +	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
> +		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",
> +			 __func__);
> +		rtl8xxxu_set_ampdu_factor(priv, 0);
> +		rtl8xxxu_set_ampdu_min_space(priv, 0);
> +		break;
> +	case IEEE80211_AMPDU_RX_START:
> +		dev_info(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);
> +		break;
> +	case IEEE80211_AMPDU_RX_STOP:
> +		dev_info(dev, "%s: IEEE80211_AMPDU_RX_STOP\n", __func__);
> +		break;
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static int rtl8xxxu_sta_add(struct ieee80211_hw *hw,
> +			    struct ieee80211_vif *vif,
> +			    struct ieee80211_sta *sta)
> +{
> +	struct rtl8xxxu_sta_priv *sta_priv;
> +
> +	sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
> +
> +	sta_priv->short_preamble = false;
> +	return 0;
> +};
> +
> +static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw,
> +			       struct ieee80211_vif *vif,
> +			       struct ieee80211_sta *sta)
> +{
> +	return 0;
> +};
> +
> +static int rtl8xxxu_start(struct ieee80211_hw *hw)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +	struct rtl8xxxu_rx_urb *rx_urb;
> +	int ret, i;
> +
> +	ret = 0;
> +
> +	init_usb_anchor(&priv->rx_anchor);
> +	init_usb_anchor(&priv->tx_anchor);
> +	init_usb_anchor(&priv->int_anchor);
> +
> +	rtl8723a_enable_rf(priv);
> +	ret = rtl8xxxu_submit_int_urb(hw);
> +	if (ret)
> +		goto exit;
> +
> +	for (i = 0; i < 32; i++) {
> +		rx_urb = kmalloc(sizeof(struct rtl8xxxu_rx_urb), GFP_ATOMIC);
> +		if (!rx_urb) {
> +			if (!i)
> +				ret = -ENOMEM;
> +
> +			goto exit;
> +		}
> +		usb_init_urb(&rx_urb->urb);
> +		rx_urb->hw = hw;
> +
> +		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
> +	}
> +exit:
> +	/*
> +	 * Disable all data frames
> +	 */
> +	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
> +	/*
> +	 * Accept all mgmt frames
> +	 */
> +	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff);
> +
> +	rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e);
> +
> +	return ret;
> +}
> +
> +static void rtl8xxxu_stop(struct ieee80211_hw *hw)
> +{
> +	struct rtl8xxxu_priv *priv = hw->priv;
> +
> +	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
> +
> +	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000);
> +	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
> +
> +	usb_kill_anchored_urbs(&priv->rx_anchor);
> +	usb_kill_anchored_urbs(&priv->tx_anchor);
> +	usb_kill_anchored_urbs(&priv->int_anchor);
> +
> +	rtl8723a_disable_rf(priv);
> +
> +	/*
> +	 * Disable interrupts
> +	 */
> +	rtl8xxxu_write32(priv, REG_USB_HIMR, 0);
> +}
> +
> +static const struct ieee80211_ops rtl8xxxu_ops = {
> +	.tx = rtl8xxxu_tx,
> +	.add_interface = rtl8xxxu_add_interface,
> +	.remove_interface = rtl8xxxu_remove_interface,
> +	.config = rtl8xxxu_config,
> +	.conf_tx = rtl8xxxu_conf_tx,
> +	.bss_info_changed = rtl8xxxu_bss_info_changed,
> +	.configure_filter = rtl8xxxu_configure_filter,
> +	.set_rts_threshold = rtl8xxxu_set_rts_threshold,
> +	.start = rtl8xxxu_start,
> +	.stop = rtl8xxxu_stop,
> +	.sw_scan_start = rtl8xxxu_sw_scan_start,
> +	.sw_scan_complete = rtl8xxxu_sw_scan_complete,
> +	.set_key = rtl8xxxu_set_key,
> +	.ampdu_action = rtl8xxxu_ampdu_action,
> +	.sta_add = rtl8xxxu_sta_add,
> +	.sta_remove = rtl8xxxu_sta_remove,
> +};
> +
> +static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv,
> +			      struct usb_interface *interface)
> +{
> +	struct usb_interface_descriptor *interface_desc;
> +	struct usb_host_interface *host_interface;
> +	struct usb_endpoint_descriptor *endpoint;
> +	struct device *dev = &priv->udev->dev;
> +	int i, j = 0, endpoints;
> +	u8 dir, xtype, num;
> +	int ret = 0;
> +
> +	host_interface = &interface->altsetting[0];
> +	interface_desc = &host_interface->desc;
> +	endpoints = interface_desc->bNumEndpoints;
> +
> +	for (i = 0; i < endpoints; i++) {
> +		endpoint = &host_interface->endpoint[i].desc;
> +
> +		dir = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
> +		num = usb_endpoint_num(endpoint);
> +		xtype = usb_endpoint_type(endpoint);
> +		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
> +			dev_dbg(dev,
> +				"%s: endpoint: dir %02x, # %02x, type %02x\n",
> +				__func__, dir, num, xtype);
> +		if (usb_endpoint_dir_in(endpoint) &&
> +		    usb_endpoint_xfer_bulk(endpoint)) {
> +			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
> +				dev_dbg(dev, "%s: in endpoint num %i\n",
> +					__func__, num);
> +
> +			if (priv->pipe_in) {
> +				dev_warn(dev,
> +					 "%s: Too many IN pipes\n", __func__);
> +				ret = -EINVAL;
> +				goto exit;
> +			}
> +
> +			priv->pipe_in =	usb_rcvbulkpipe(priv->udev, num);
> +		}
> +
> +		if (usb_endpoint_dir_in(endpoint) &&
> +		    usb_endpoint_xfer_int(endpoint)) {
> +			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
> +				dev_dbg(dev, "%s: interrupt endpoint num %i\n",
> +					__func__, num);
> +
> +			if (priv->pipe_interrupt) {
> +				dev_warn(dev, "%s: Too many INTERRUPT pipes\n",
> +					 __func__);
> +				ret = -EINVAL;
> +				goto exit;
> +			}
> +
> +			priv->pipe_interrupt = usb_rcvintpipe(priv->udev, num);
> +		}
> +
> +		if (usb_endpoint_dir_out(endpoint) &&
> +		    usb_endpoint_xfer_bulk(endpoint)) {
> +			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
> +				dev_dbg(dev, "%s: out endpoint num %i\n",
> +					__func__, num);
> +			if (j >= RTL8XXXU_OUT_ENDPOINTS) {
> +				dev_warn(dev,
> +					 "%s: Too many OUT pipes\n", __func__);
> +				ret = -EINVAL;
> +				goto exit;
> +			}
> +			priv->out_ep[j++] = num;
> +		}
> +	}
> +exit:
> +	priv->nr_out_eps = j;
> +	return ret;
> +}
> +
> +static int rtl8xxxu_probe(struct usb_interface *interface,
> +			  const struct usb_device_id *id)
> +{
> +	struct rtl8xxxu_priv *priv;
> +	struct ieee80211_hw *hw;
> +	struct usb_device *udev;
> +	struct ieee80211_supported_band *sband;
> +	int ret = 0;
> +	int untested = 1;
> +
> +	udev = usb_get_dev(interface_to_usbdev(interface));
> +
> +	switch (id->idVendor) {
> +	case USB_VENDOR_ID_REALTEK:
> +		switch(id->idProduct) {
> +		case 0x1724:
> +		case 0x8176:
> +		case 0x8178:
> +		case 0x817f:
> +			untested = 0;
> +			break;
> +		}
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	if (untested) {
> +		rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE;
> +		dev_info(&udev->dev,
> +			 "This Realtek USB WiFi dongle (0x%04x:0x%04x) is untested!\n",
> +			 id->idVendor, id->idProduct);
> +		dev_info(&udev->dev,
> +			 "Please report results to Jes.Sorensen@gmail.com\n");
> +	}
> +
> +	hw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), &rtl8xxxu_ops);
> +	if (!hw) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	priv = hw->priv;
> +	priv->hw = hw;
> +	priv->udev = udev;
> +	priv->fops = (struct rtl8xxxu_fileops *)id->driver_info;
> +	mutex_init(&priv->usb_buf_mutex);
> +	mutex_init(&priv->h2c_mutex);
> +
> +	usb_set_intfdata(interface, hw);
> +
> +	ret = rtl8xxxu_parse_usb(priv, interface);
> +	if (ret)
> +		goto exit;
> +
> +	ret = rtl8xxxu_identify_chip(priv);
> +	if (ret) {
> +		dev_err(&udev->dev, "Fatal - failed to identify chip\n");
> +		goto exit;
> +	}
> +
> +	ret = rtl8xxxu_read_efuse(priv);
> +	if (ret) {
> +		dev_err(&udev->dev, "Fatal - failed to read EFuse\n");
> +		goto exit;
> +	}
> +
> +	ret = priv->fops->parse_efuse(priv);
> +	if (ret) {
> +		dev_err(&udev->dev, "Fatal - failed to parse EFuse\n");
> +		goto exit;
> +	}
> +
> +	rtl8xxxu_print_chipinfo(priv);
> +
> +	ret = priv->fops->load_firmware(priv);
> +	if (ret) {
> +		dev_err(&udev->dev, "Fatal - failed to load firmware\n");
> +		goto exit;
> +	}
> +
> +	ret = rtl8xxxu_init_device(hw);
> +
> +	hw->wiphy->max_scan_ssids = 1;
> +	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
> +	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
> +	hw->queues = 4;
> +
> +	sband = &rtl8xxxu_supported_band;
> +	sband->ht_cap.ht_supported = true;
> +	sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
> +	sband->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
> +	sband->ht_cap.cap = /* IEEE80211_HT_CAP_SUP_WIDTH_20_40 | */
> +		IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40;
> +	memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs));
> +	sband->ht_cap.mcs.rx_mask[0] = 0xff;
> +	sband->ht_cap.mcs.rx_mask[4] = 0x01;
> +	if (priv->rf_paths > 1) {
> +		sband->ht_cap.mcs.rx_mask[1] = 0xff;
> +		sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
> +	}
> +	sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
> +	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
> +
> +	hw->wiphy->rts_threshold = 2347;
> +
> +	SET_IEEE80211_DEV(priv->hw, &interface->dev);
> +	SET_IEEE80211_PERM_ADDR(hw, priv->mac_addr);
> +
> +	hw->extra_tx_headroom = sizeof(struct rtl8xxxu_tx_desc);
> +	hw->sta_data_size = sizeof(struct rtl8xxxu_sta_priv);
> +	ieee80211_hw_set(hw, SIGNAL_DBM);
> +	/*
> +	 * The firmware handles rate control
> +	 */
> +	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
> +	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
> +
> +	ret = ieee80211_register_hw(priv->hw);
> +	if (ret) {
> +		dev_err(&udev->dev, "%s: Failed to register: %i\n",
> +			__func__, ret);
> +		goto exit;
> +	}
> +
> +exit:
> +	if (ret < 0)
> +		usb_put_dev(udev);
> +	return ret;
> +}
> +
> +static void rtl8xxxu_disconnect(struct usb_interface *interface)
> +{
> +	struct rtl8xxxu_priv *priv;
> +	struct ieee80211_hw *hw;
> +
> +	hw = usb_get_intfdata(interface);
> +	priv = hw->priv;
> +
> +	rtl8xxxu_disable_device(hw);
> +	usb_set_intfdata(interface, NULL);
> +
> +	dev_info(&priv->udev->dev, "disconnecting\n");
> +
> +	ieee80211_unregister_hw(hw);
> +
> +	kfree(priv->fw_data);
> +	mutex_destroy(&priv->usb_buf_mutex);
> +	mutex_destroy(&priv->h2c_mutex);
> +
> +	usb_put_dev(priv->udev);
> +	ieee80211_free_hw(hw);
> +}
> +
> +static struct rtl8xxxu_fileops rtl8723au_fops = {
> +	.parse_efuse = rtl8723au_parse_efuse,
> +	.load_firmware = rtl8723au_load_firmware,
> +	.power_on = rtl8723au_power_on,
> +	.writeN = rtl8xxxu_writeN,
> +};
> +
> +static struct rtl8xxxu_fileops rtl8192cu_fops = {
> +	.parse_efuse = rtl8192cu_parse_efuse,
> +	.load_firmware = rtl8192cu_load_firmware,
> +	.power_on = rtl8192cu_power_on,
> +	.writeN = rtl8xxxu_slow_writeN,
> +};
> +
> +static struct usb_device_id dev_table[] = {
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8723au_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1724, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8723au_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0724, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8723au_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8178, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817f, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +#ifdef CONFIG_RTL8XXXU_UNTESTED
> +/* Currently untested 8188 series devices */
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8177, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817a, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817b, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817d, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},

I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.

> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818a, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x1058, 0x0631, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x094c, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1102, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ba, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1e1e, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x5088, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0052, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x005c, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0eb0, 0x9071, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x103c, 0x1629, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x13d3, 0x3357, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330b, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x4902, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2a, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2e, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xed17, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x648b, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0090, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x4856, 0x0091, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7811, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffa, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff8, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffb, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffc, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x1201, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +/* Currently untested 8192 series devices */
> +{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0950, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2102, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2103, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x341f, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe035, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ab, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0061, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0070, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0789, 0x016d, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x07aa, 0x0056, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8178, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9021, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0xf001, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x2e2e, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0019, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0020, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3307, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3309, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330a, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2b, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x624d, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0100, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0091, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff),
> +	.driver_info = (unsigned long)&rtl8192cu_fops},
> +#endif
> +{ }
> +};
> +
> +static struct usb_driver rtl8xxxu_driver = {
> +	.name = DRIVER_NAME,
> +	.probe = rtl8xxxu_probe,
> +	.disconnect = rtl8xxxu_disconnect,
> +	.id_table = dev_table,
> +	.disable_hub_initiated_lpm = 1,
> +};
> +
> +static int __init rtl8xxxu_module_init(void)
> +{
> +	int res;
> +
> +	res = usb_register(&rtl8xxxu_driver);
> +	if (res < 0)
> +		pr_err(DRIVER_NAME ": usb_register() failed (%i)\n", res);
> +
> +	return res;
> +}
> +
> +static void __exit rtl8xxxu_module_exit(void)
> +{
> +	usb_deregister(&rtl8xxxu_driver);
> +}
> +
> +
> +MODULE_DEVICE_TABLE(usb, dev_table);
> +
> +module_init(rtl8xxxu_module_init);
> +module_exit(rtl8xxxu_module_exit);
> diff --git a/drivers/net/wireless/rtl8xxxu.h b/drivers/net/wireless/rtl8xxxu.h
> new file mode 100644
> index 0000000..ad499f9
> --- /dev/null
> +++ b/drivers/net/wireless/rtl8xxxu.h
> @@ -0,0 +1,597 @@
> +/*
> + * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * Register definitions taken from original Realtek rtl8723au driver
> + */
> +
> +#include <asm/byteorder.h>
> +
> +#define RTL8XXXU_DEBUG_REG_WRITE	0x01
> +#define RTL8XXXU_DEBUG_REG_READ		0x02
> +#define RTL8XXXU_DEBUG_RFREG_WRITE	0x04
> +#define RTL8XXXU_DEBUG_RFREG_READ	0x08
> +#define RTL8XXXU_DEBUG_CHANNEL		0x10
> +#define RTL8XXXU_DEBUG_TX		0x20
> +#define RTL8XXXU_DEBUG_TX_DUMP		0x40
> +#define RTL8XXXU_DEBUG_RX		0x80
> +#define RTL8XXXU_DEBUG_RX_DUMP		0x100
> +#define RTL8XXXU_DEBUG_USB		0x200
> +#define RTL8XXXU_DEBUG_KEY		0x400
> +#define RTL8XXXU_DEBUG_H2C		0x800
> +#define RTL8XXXU_DEBUG_ACTION		0x1000
> +#define RTL8XXXU_DEBUG_EFUSE		0x2000
> +
> +#define RTW_USB_CONTROL_MSG_TIMEOUT	500
> +#define RTL8XXXU_MAX_REG_POLL		500
> +#define	USB_INTR_CONTENT_LENGTH		56
> +
> +#define RTL8XXXU_OUT_ENDPOINTS		3
> +
> +#define REALTEK_USB_READ		0xc0
> +#define REALTEK_USB_WRITE		0x40
> +#define REALTEK_USB_CMD_REQ		0x05
> +#define REALTEK_USB_CMD_IDX		0x00
> +
> +#define TX_TOTAL_PAGE_NUM		0xf8
> +/* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */
> +#define TX_PAGE_NUM_PUBQ		0xe7
> +#define TX_PAGE_NUM_HI_PQ		0x0c
> +#define TX_PAGE_NUM_LO_PQ		0x02
> +#define TX_PAGE_NUM_NORM_PQ		0x02
> +
> +#define RTL_FW_PAGE_SIZE		4096
> +#define RTL8XXXU_FIRMWARE_POLL_MAX	1000
> +
> +#define RTL8723A_CHANNEL_GROUPS		3
> +#define RTL8723A_MAX_RF_PATHS		2
> +#define RF6052_MAX_TX_PWR		0x3f
> +
> +#define EFUSE_MAP_LEN_8723A		256
> +#define EFUSE_MAX_SECTION_8723A		32
> +#define EFUSE_REAL_CONTENT_LEN_8723A	512
> +#define EFUSE_BT_MAP_LEN_8723A		1024
> +#define EFUSE_MAX_WORD_UNIT		4
> +
> +struct rtl8xxxu_rx_desc {
> +	u32 pktlen:14;
> +	u32 crc32:1;
> +	u32 icverr:1;
> +	u32 drvinfo_sz:4;
> +	u32 security:3;
> +	u32 qos:1;
> +	u32 shift:2;
> +	u32 phy_stats:1;
> +	u32 swdec:1;
> +	u32 ls:1;
> +	u32 fs:1;
> +	u32 eor:1;
> +	u32 own:1;
> +
> +	u32 macid:5;
> +	u32 tid:4;
> +	u32 hwrsvd:4;
> +	u32 amsdu:1;
> +	u32 paggr:1;
> +	u32 faggr:1;
> +	u32 a1fit:4;
> +	u32 a2fit:4;
> +	u32 pam:1;
> +	u32 pwr:1;
> +	u32 md:1;
> +	u32 mf:1;
> +	u32 type:2;
> +	u32 mc:1;
> +	u32 bc:1;
> +
> +	u32 seq:12;
> +	u32 frag:4;
> +	u32 nextpktlen:14;
> +	u32 nextind:1;
> +	u32 reserved0:1;
> +
> +	u32 rxmcs:6;
> +	u32 rxht:1;
> +	u32 gf:1;
> +	u32 splcp:1;
> +	u32 bw:1;
> +	u32 htc:1;
> +	u32 eosp:1;
> +	u32 bssidfit:2;
> +	u32 reserved1:16;
> +	u32 unicastwake:1;
> +	u32 magicwake:1;
> +
> +	u32 pattern0match:1;
> +	u32 pattern1match:1;
> +	u32 pattern2match:1;
> +	u32 pattern3match:1;
> +	u32 pattern4match:1;
> +	u32 pattern5match:1;
> +	u32 pattern6match:1;
> +	u32 pattern7match:1;
> +	u32 pattern8match:1;
> +	u32 pattern9match:1;
> +	u32 patternamatch:1;
> +	u32 patternbmatch:1;
> +	u32 patterncmatch:1;
> +	u32 reserved2:19;
> +
> +	__le32 tsfl;
> +#if 0
> +	u32 bassn:12;
> +	u32 bavld:1;
> +	u32 reserved3:19;
> +#endif
> +};
> +
> +struct rtl8xxxu_tx_desc {
> +	__le16 pkt_size;
> +	u8 pkt_offset;
> +	u8 txdw0;
> +	__le32 txdw1;
> +	__le32 txdw2;
> +	__le32 txdw3;
> +	__le32 txdw4;
> +	__le32 txdw5;
> +	__le32 txdw6;
> +	__le16 csum;
> +	__le16 txdw7;
> +};
> +
> +/*  CCK Rates, TxHT = 0 */
> +#define DESC_RATE_1M			0x00
> +#define DESC_RATE_2M			0x01
> +#define DESC_RATE_5_5M			0x02
> +#define DESC_RATE_11M			0x03
> +
> +/*  OFDM Rates, TxHT = 0 */
> +#define DESC_RATE_6M			0x04
> +#define DESC_RATE_9M			0x05
> +#define DESC_RATE_12M			0x06
> +#define DESC_RATE_18M			0x07
> +#define DESC_RATE_24M			0x08
> +#define DESC_RATE_36M			0x09
> +#define DESC_RATE_48M			0x0a
> +#define DESC_RATE_54M			0x0b
> +
> +/*  MCS Rates, TxHT = 1 */
> +#define DESC_RATE_MCS0			0x0c
> +#define DESC_RATE_MCS1			0x0d
> +#define DESC_RATE_MCS2			0x0e
> +#define DESC_RATE_MCS3			0x0f
> +#define DESC_RATE_MCS4			0x10
> +#define DESC_RATE_MCS5			0x11
> +#define DESC_RATE_MCS6			0x12
> +#define DESC_RATE_MCS7			0x13
> +#define DESC_RATE_MCS8			0x14
> +#define DESC_RATE_MCS9			0x15
> +#define DESC_RATE_MCS10			0x16
> +#define DESC_RATE_MCS11			0x17
> +#define DESC_RATE_MCS12			0x18
> +#define DESC_RATE_MCS13			0x19
> +#define DESC_RATE_MCS14			0x1a
> +#define DESC_RATE_MCS15			0x1b
> +#define DESC_RATE_MCS15_SG		0x1c
> +#define DESC_RATE_MCS32			0x20
> +
> +#define TXDESC_OFFSET_SZ		0
> +#define TXDESC_OFFSET_SHT		16
> +#if 0
> +#define TXDESC_BMC			BIT(24)
> +#define TXDESC_LSG			BIT(26)
> +#define TXDESC_FSG			BIT(27)
> +#define TXDESC_OWN			BIT(31)
> +#else
> +#define TXDESC_BROADMULTICAST		BIT(0)
> +#define TXDESC_LAST_SEGMENT		BIT(2)
> +#define TXDESC_FIRST_SEGMENT		BIT(3)
> +#define TXDESC_OWN			BIT(7)
> +#endif
> +
> +/* Word 1 */
> +#define TXDESC_PKT_OFFSET_SZ		0
> +#define TXDESC_AGG_ENABLE		BIT(5)
> +#define TXDESC_BK			BIT(6)
> +#define TXDESC_QUEUE_SHIFT		8
> +#define TXDESC_QUEUE_MASK		0x1f00
> +#define TXDESC_QUEUE_BK			0x2
> +#define TXDESC_QUEUE_BE			0x0
> +#define TXDESC_QUEUE_VI			0x5
> +#define TXDESC_QUEUE_VO			0x7
> +#define TXDESC_QUEUE_BEACON		0x10
> +#define TXDESC_QUEUE_HIGH		0x11
> +#define TXDESC_QUEUE_MGNT		0x12
> +#define TXDESC_QUEUE_CMD		0x13
> +#define TXDESC_QUEUE_MAX		(TXDESC_QUEUE_CMD + 1)
> +
> +#define DESC_RATE_ID_SHIFT		16
> +#define DESC_RATE_ID_MASK		0xf
> +#define TXDESC_NAVUSEHDR		BIT(20)
> +#define TXDESC_SEC_RC4			0x00400000
> +#define TXDESC_SEC_AES			0x00c00000
> +#define TXDESC_PKT_OFFSET_SHIFT		26
> +#define TXDESC_AGG_EN			BIT(29)
> +#define TXDESC_HWPC			BIT(31)
> +
> +/* Word 2 */
> +#define TXDESC_ACK_REPORT		BIT(19)
> +#define TXDESC_AMPDU_DENSITY_SHIFT	20
> +
> +/* Word 3 */
> +#define TXDESC_SEQ_SHIFT		16
> +#define TXDESC_SEQ_MASK			0x0fff0000
> +
> +/* Word 4 */
> +#define TXDESC_QOS			BIT(6)
> +#define TXDESC_HW_SEQ_ENABLE		BIT(7)
> +#define TXDESC_USE_DRIVER_RATE		BIT(8)
> +#define TXDESC_DISABLE_DATA_FB		BIT(10)
> +#define TXDESC_CTS_SELF_ENABLE		BIT(11)
> +#define TXDESC_RTS_CTS_ENABLE		BIT(12)
> +#define TXDESC_HW_RTS_ENABLE		BIT(13)
> +#define TXDESC_PRIME_CH_OFF_LOWER	BIT(20)
> +#define TXDESC_PRIME_CH_OFF_UPPER	BIT(21)
> +#define TXDESC_SHORT_PREAMBLE		BIT(24)
> +#define TXDESC_DATA_BW			BIT(25)
> +#define TXDESC_RTS_DATA_BW		BIT(27)
> +#define TXDESC_RTS_PRIME_CH_OFF_LOWER	BIT(28)
> +#define TXDESC_RTS_PRIME_CH_OFF_UPPER	BIT(29)
> +
> +/* Word 5 */
> +#define TXDESC_RTS_RATE_SHIFT		0
> +#define TXDESC_RTS_RATE_MASK		0x3f
> +#define TXDESC_SHORT_GI			BIT(6)
> +#define TXDESC_CCX_TAG			BIT(7)
> +#define TXDESC_RETRY_LIMIT_ENABLE	BIT(17)
> +#define TXDESC_RETRY_LIMIT_SHIFT	18
> +#define TXDESC_RETRY_LIMIT_MASK		0x00fc0000
> +
> +/* Word 6 */
> +#define TXDESC_MAX_AGG_SHIFT		11
> +
> +struct phy_rx_agc_info {
> +#ifdef __LITTLE_ENDIAN
> +	u8	gain:7, trsw:1;
> +#else
> +	u8	trsw:1, gain:7;
> +#endif
> +};
> +
> +struct rtl8723au_phy_stats {
> +	struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS];
> +	u8	ch_corr[RTL8723A_MAX_RF_PATHS];
> +	u8	cck_sig_qual_ofdm_pwdb_all;
> +	u8	cck_agc_rpt_ofdm_cfosho_a;
> +	u8	cck_rpt_b_ofdm_cfosho_b;
> +	u8	reserved_1;
> +	u8	noise_power_db_msb;
> +	u8	path_cfotail[RTL8723A_MAX_RF_PATHS];
> +	u8	pcts_mask[RTL8723A_MAX_RF_PATHS];
> +	s8	stream_rxevm[RTL8723A_MAX_RF_PATHS];
> +	u8	path_rxsnr[RTL8723A_MAX_RF_PATHS];
> +	u8	noise_power_db_lsb;
> +	u8	reserved_2[3];
> +	u8	stream_csi[RTL8723A_MAX_RF_PATHS];
> +	u8	stream_target_csi[RTL8723A_MAX_RF_PATHS];
> +	s8	sig_evm;
> +	u8	reserved_3;
> +
> +#ifdef __LITTLE_ENDIAN
> +	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
> +	u8	sgi_en:1;
> +	u8	rxsc:2;
> +	u8	idle_long:1;
> +	u8	r_ant_train_en:1;
> +	u8	antenna_select_b:1;
> +	u8	antenna_select:1;
> +#else	/*  _BIG_ENDIAN_ */
> +	u8	antenna_select:1;
> +	u8	antenna_select_b:1;
> +	u8	r_ant_train_en:1;
> +	u8	idle_long:1;
> +	u8	rxsc:2;
> +	u8	sgi_en:1;
> +	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
> +#endif
> +};
> +
> +/*
> + * Regs to backup
> + */
> +#define RTL8XXXU_ADDA_REGS		16
> +#define RTL8XXXU_MAC_REGS		4
> +#define RTL8XXXU_BB_REGS		9
> +
> +struct rtl8xxxu_firmware_header {
> +	__le16	signature;		/*  92C0: test chip; 92C,
> +					    88C0: test chip;
> +					    88C1: MP A-cut;
> +					    92C1: MP A-cut */
> +	u8	category;		/*  AP/NIC and USB/PCI */
> +	u8	function;
> +
> +	__le16	major_version;		/*  FW Version */
> +	u8	minor_version;		/*  FW Subversion, default 0x00 */
> +	u8	reserved1;
> +
> +	u8	month;			/*  Release time Month field */
> +	u8	date;			/*  Release time Date field */
> +	u8	hour;			/*  Release time Hour field */
> +	u8	minute;			/*  Release time Minute field */
> +
> +	__le16	ramcodesize;		/*  Size of RAM code */
> +	u16	reserved2;
> +
> +	__le32	svn_idx;		/*  SVN entry index */
> +	u32	reserved3;
> +
> +	u32	reserved4;
> +	u32	reserved5;
> +
> +	u8	data[0];
> +};
> +
> +/*
> + * The 8723au has 3 channel groups: 1-3, 4-9, and 10-14
> + */
> +struct rtl8723au_idx {
> +#ifdef __LITTLE_ENDIAN
> +	int	a:4;
> +	int	b:4;
> +#else
> +	int	b:4;
> +	int	a:4;
> +#endif
> +} __attribute__((packed));
> +
> +struct rtl8723au_efuse {
> +	__le16 rtl_id;
> +	u8 res0[0xe];
> +	u8 cck_tx_power_index_A[3];	/* 0x10 */
> +	u8 cck_tx_power_index_B[3];
> +	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
> +	u8 ht40_1s_tx_power_index_B[3];
> +	/*
> +	 * The following entries are half-bytes split as:
> +	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
> +	 */
> +	struct rtl8723au_idx ht20_tx_power_index_diff[3];
> +	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
> +	struct rtl8723au_idx ht40_max_power_offset[3];
> +	struct rtl8723au_idx ht20_max_power_offset[3];
> +	u8 channel_plan;		/* 0x28 */
> +	u8 tssi_a;
> +	u8 thermal_meter;
> +	u8 rf_regulatory;
> +	u8 rf_option_2;
> +	u8 rf_option_3;
> +	u8 rf_option_4;
> +	u8 res7;
> +	u8 version			/* 0x30 */;
> +	u8 customer_id_major;
> +	u8 customer_id_minor;
> +	u8 xtal_k;
> +	u8 chipset;			/* 0x34 */
> +	u8 res8[0x82];
> +	u8 vid;				/* 0xb7 */
> +	u8 res9;
> +	u8 pid;				/* 0xb9 */
> +	u8 res10[0x0c];
> +	u8 mac_addr[ETH_ALEN];		/* 0xc6 */
> +	u8 res11[2];
> +	u8 vendor_name[7];
> +	u8 res12[2];
> +	u8 device_name[0x29];		/* 0xd7 */
> +};
> +
> +struct rtl8192cu_efuse {
> +	__le16 rtl_id;
> +	__le16 hpon;
> +	u8 res0[2];
> +	__le16 clk;
> +	__le16 testr;
> +	__le16 vid;
> +	__le16 did;
> +	__le16 svid;
> +	__le16 smid;						/* 0x10 */
> +	u8 res1[4];
> +	u8 mac_addr[ETH_ALEN];					/* 0x16 */
> +	u8 res2[2];
> +	u8 vendor_name[7];
> +	u8 res3[3];
> +	u8 device_name[0x14];					/* 0x28 */
> +	u8 res4[0x1e];						/* 0x3c */
> +	u8 cck_tx_power_index_A[3];				/* 0x5a */
> +	u8 cck_tx_power_index_B[3];
> +	u8 ht40_1s_tx_power_index_A[3];				/* 0x60 */
> +	u8 ht40_1s_tx_power_index_B[3];
> +	u8 ht40_2s_tx_power_index_diff[3];
> +	/*
> +	 * The following entries are half-bytes split as:
> +	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
> +	 */
> +	struct rtl8723au_idx ht20_tx_power_index_diff[3];	/* 0x69 */
> +	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
> +	struct rtl8723au_idx ht40_max_power_offset[3];		/* 0x6f */
> +	struct rtl8723au_idx ht20_max_power_offset[3];
> +	u8 channel_plan;					/* 0x75 */
> +	u8 tssi_a;
> +	u8 tssi_b;
> +	u8 thermal_meter;	/* xtal_k */			/* 0x78 */
> +	u8 rf_regulatory;
> +	u8 rf_option_2;
> +	u8 rf_option_3;
> +	u8 rf_option_4;
> +	u8 res5[1];						/* 0x7d */
> +	u8 version;
> +	u8 customer_id;
> +};
> +
> +struct rtl8xxxu_reg8val {
> +	u16 reg;
> +	u8 val;
> +};
> +
> +struct rtl8xxxu_reg32val {
> +	u16 reg;
> +	u32 val;
> +};
> +
> +struct rtl8xxxu_rfregval {
> +	u8 reg;
> +	u32 val;
> +};
> +
> +enum rtl8xxxu_rfpath {
> +	RF_A = 0,
> +	RF_B = 1,
> +};
> +
> +struct rtl8xxxu_rfregs {
> +	u16 hssiparm1;
> +	u16 hssiparm2;
> +	u16 lssiparm;
> +	u16 hspiread;
> +	u16 lssiread;
> +	u16 rf_sw_ctrl;
> +};
> +
> +#define H2C_MAX_MBOX			4
> +#define H2C_EXT				BIT(7)
> +#define H2C_SET_POWER_MODE		1
> +#define H2C_JOIN_BSS_REPORT		2
> +#define  H2C_JOIN_BSS_DISCONNECT	0
> +#define  H2C_JOIN_BSS_CONNECT		1
> +#define H2C_SET_RSSI			5
> +#define H2C_SET_RATE_MASK		(6 | H2C_EXT)
> +
> +struct h2c_cmd {
> +	union {
> +		struct {
> +			u8 cmd;
> +			u8 data[5];
> +		} __packed cmd;
> +		struct {
> +			__le32 data;
> +			__le16 ext;
> +		} __packed raw;
> +		struct {
> +			u8 cmd;
> +			u8 data;
> +			u8 pad[4];
> +		} __packed joinbss;
> +		struct {
> +			u8 cmd;
> +			__le16 mask_hi;
> +			u8 arg;
> +			__le16 mask_lo;
> +		} __packed ramask;
> +	};
> +};
> +
> +struct rtl8xxxu_fileops;
> +
> +struct rtl8xxxu_priv {
> +	struct ieee80211_hw *hw;
> +	struct usb_device *udev;
> +	struct rtl8xxxu_fileops *fops;
> +	u8 mac_addr[ETH_ALEN];
> +	char chip_name[8];
> +	u8 cck_tx_power_index_A[3];	/* 0x10 */
> +	u8 cck_tx_power_index_B[3];
> +	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
> +	u8 ht40_1s_tx_power_index_B[3];
> +	u8 ht40_2s_tx_power_index_diff[3];
> +	/*
> +	 * The following entries are half-bytes split as:
> +	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
> +	 */
> +	struct rtl8723au_idx ht20_tx_power_index_diff[3];
> +	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
> +	struct rtl8723au_idx ht40_max_power_offset[3];
> +	struct rtl8723au_idx ht20_max_power_offset[3];
> +	u32 chip_cut:4;
> +	u32 rom_rev:4;
> +	u32 has_wifi:1;
> +	u32 has_bluetooth:1;
> +	u32 enable_bluetooth:1;
> +	u32 has_gps:1;
> +	u32 hi_pa:1;
> +	u32 vendor_umc:1;
> +	u32 has_polarity_ctrl:1;
> +	u32 has_eeprom:1;
> +	u32 boot_eeprom:1;
> +	u32 ep_tx_high_queue:1;
> +	u32 ep_tx_normal_queue:1;
> +	u32 ep_tx_low_queue:1;
> +	u32 path_a_hi_power:1;
> +	u32 path_a_rf_paths:4;
> +	unsigned int pipe_interrupt;
> +	unsigned int pipe_in;
> +	unsigned int pipe_out[TXDESC_QUEUE_MAX];
> +	u8 out_ep[RTL8XXXU_OUT_ENDPOINTS];
> +	u8 path_a_ig_value;
> +	u8 ep_tx_count;
> +	u8 rf_paths;
> +	u8 rx_paths;
> +	u8 tx_paths;
> +	u32 rf_mode_ag[2];
> +	u32 rege94;
> +	u32 rege9c;
> +	u32 regeb4;
> +	u32 regebc;
> +	int next_mbox;
> +	int nr_out_eps;
> +
> +	struct mutex h2c_mutex;
> +
> +	struct usb_anchor rx_anchor;
> +	struct usb_anchor tx_anchor;
> +	struct usb_anchor int_anchor;
> +	struct rtl8xxxu_firmware_header *fw_data;
> +	size_t fw_size;
> +	struct mutex usb_buf_mutex;
> +	union {
> +		__le32 val32;
> +		__le16 val16;
> +		u8 val8;
> +	} usb_buf;
> +	union {
> +		u8 raw[EFUSE_MAP_LEN_8723A];
> +		struct rtl8723au_efuse efuse8723;
> +		struct rtl8192cu_efuse efuse8192;
> +	} efuse_wifi;
> +	u32 adda_backup[RTL8XXXU_ADDA_REGS];
> +	u32 mac_backup[RTL8XXXU_MAC_REGS];
> +	u32 bb_backup[RTL8XXXU_BB_REGS];
> +	u32 bb_recovery_backup[RTL8XXXU_BB_REGS];
> +	u32 rtlchip;
> +	u8 pi_enabled:1;
> +	u8 iqk_initialized:1;
> +	u8 int_buf[USB_INTR_CONTENT_LENGTH];
> +};
> +
> +struct rtl8xxxu_rx_urb {
> +	struct urb urb;
> +	struct ieee80211_hw *hw;
> +};
> +
> +struct rtl8xxxu_sta_priv {
> +	bool short_preamble;
> +};
> +
> +struct rtl8xxxu_fileops {
> +	int (*parse_efuse) (struct rtl8xxxu_priv *priv);
> +	int (*load_firmware) (struct rtl8xxxu_priv *priv);
> +	int (*power_on) (struct rtl8xxxu_priv *priv);
> +	int (*writeN) (struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len);
> +};
> diff --git a/drivers/net/wireless/rtl8xxxu_regs.h b/drivers/net/wireless/rtl8xxxu_regs.h
> new file mode 100644
> index 0000000..a7aa569
> --- /dev/null
> +++ b/drivers/net/wireless/rtl8xxxu_regs.h
> @@ -0,0 +1,980 @@
> +/*
> + * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * Register definitions taken from original Realtek rtl8723au driver
> + */
> +
> +/* 0x0000 ~ 0x00FF	System Configuration */
> +#define REG_SYS_ISO_CTRL		0x0000
> +#define  SYS_ISO_MD2PP			BIT(0)
> +#define  SYS_ISO_ANALOG_IPS		BIT(5)
> +#define  SYS_ISO_DIOR			BIT(9)
> +#define  SYS_ISO_PWC_EV25V		BIT(14)
> +#define  SYS_ISO_PWC_EV12V		BIT(15)
> +
> +#define REG_SYS_FUNC			0x0002
> +#define  SYS_FUNC_BBRSTB		BIT(0)
> +#define  SYS_FUNC_BB_GLB_RSTN		BIT(1)
> +#define  SYS_FUNC_USBA			BIT(2)
> +#define  SYS_FUNC_UPLL			BIT(3)
> +#define  SYS_FUNC_USBD			BIT(4)
> +#define  SYS_FUNC_DIO_PCIE		BIT(5)
> +#define  SYS_FUNC_PCIEA			BIT(6)
> +#define  SYS_FUNC_PPLL			BIT(7)
> +#define  SYS_FUNC_PCIED			BIT(8)
> +#define  SYS_FUNC_DIOE			BIT(9)
> +#define  SYS_FUNC_CPU_ENABLE		BIT(10)
> +#define  SYS_FUNC_DCORE			BIT(11)
> +#define  SYS_FUNC_ELDR			BIT(12)
> +#define  SYS_FUNC_DIO_RF		BIT(13)
> +#define  SYS_FUNC_HWPDN			BIT(14)
> +#define  SYS_FUNC_MREGEN		BIT(15)
> +
> +#define REG_APS_FSMCO			0x0004
> +#define  APS_FSMCO_PFM_ALDN		BIT(1)
> +#define  APS_FSMCO_PFM_WOWL		BIT(3)
> +#define  APS_FSMCO_ENABLE_POWERDOWN	BIT(4)
> +#define  APS_FSMCO_MAC_ENABLE		BIT(8)
> +#define  APS_FSMCO_MAC_OFF		BIT(9)
> +#define  APS_FSMCO_HW_SUSPEND		BIT(11)
> +#define  APS_FSMCO_PCIE			BIT(12)
> +#define  APS_FSMCO_HW_POWERDOWN		BIT(15)
> +#define  APS_FSMCO_WLON_RESET		BIT(16)
> +
> +#define REG_SYS_CLKR			0x0008
> +#define  SYS_CLK_ANAD16V_ENABLE		BIT(0)
> +#define  SYS_CLK_ANA8M			BIT(1)
> +#define  SYS_CLK_MACSLP			BIT(4)
> +#define  SYS_CLK_LOADER_ENABLE		BIT(5)
> +#define  SYS_CLK_80M_SSC_DISABLE	BIT(7)
> +#define  SYS_CLK_80M_SSC_ENABLE_HO	BIT(8)
> +#define  SYS_CLK_PHY_SSC_RSTB		BIT(9)
> +#define  SYS_CLK_SEC_CLK_ENABLE		BIT(10)
> +#define  SYS_CLK_MAC_CLK_ENABLE		BIT(11)
> +#define  SYS_CLK_ENABLE			BIT(12)
> +#define  SYS_CLK_RING_CLK_ENABLE	BIT(13)
> +
> +#define REG_9346CR			0x000a
> +#define  EEPROM_BOOT			BIT(4)
> +#define  EEPROM_ENABLE			BIT(5)
> +
> +#define REG_EE_VPD			0x000c
> +#define REG_AFE_MISC			0x0010
> +#define REG_SPS0_CTRL			0x0011
> +#define REG_SPS_OCP_CFG			0x0018
> +#define REG_RSV_CTRL			0x001c
> +
> +#define REG_RF_CTRL			0x001f
> +#define  RF_ENABLE			BIT(0)
> +#define  RF_RSTB			BIT(1)
> +#define  RF_SDMRSTB			BIT(2)
> +
> +#define REG_LDOA15_CTRL			0x0020
> +#define  LDOA15_ENABLE			BIT(0)
> +#define  LDOA15_STANDBY			BIT(1)
> +#define  LDOA15_OBUF			BIT(2)
> +#define  LDOA15_REG_VOS			BIT(3)
> +#define  LDOA15_VOADJ_SHIFT		4
> +
> +#define REG_LDOV12D_CTRL		0x0021
> +#define  LDOV12D_ENABLE			BIT(0)
> +#define  LDOV12D_STANDBY		BIT(1)
> +#define  LDOV12D_VADJ_SHIFT		4
> +
> +#define REG_LDOHCI12_CTRL		0x0022
> +
> +#define REG_LPLDO_CTRL			0x0023
> +#define  LPLDO_HSM			BIT(2)
> +#define  LPLDO_LSM_DIS			BIT(3)
> +
> +#define REG_AFE_XTAL_CTRL		0x0024
> +#define  AFE_XTAL_ENABLE		BIT(0)
> +#define  AFE_XTAL_B_SELECT		BIT(1)
> +#define  AFE_XTAL_GATE_USB		BIT(8)
> +#define  AFE_XTAL_GATE_AFE		BIT(11)
> +#define  AFE_XTAL_RF_GATE		BIT(14)
> +#define  AFE_XTAL_GATE_DIG		BIT(17)
> +#define  AFE_XTAL_BT_GATE		BIT(20)
> +
> +#define REG_AFE_PLL_CTRL		0x0028
> +#define  AFE_PLL_ENABLE			BIT(0)
> +#define  AFE_PLL_320_ENABLE		BIT(1)
> +#define  APE_PLL_FREF_SELECT		BIT(2)
> +#define  AFE_PLL_EDGE_SELECT		BIT(3)
> +#define  AFE_PLL_WDOGB			BIT(4)
> +#define  AFE_PLL_LPF_ENABLE		BIT(5)
> +
> +#define REG_MAC_PHY_CTRL		0x002c
> +
> +#define REG_EFUSE_CTRL			0x0030
> +#define REG_EFUSE_TEST			0x0034
> +#define  EFUSE_TRPT			BIT(7)
> +	/*  00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
> +#define  EFUSE_CELL_SEL			(BIT(8) | BIT(9))
> +#define  EFUSE_LDOE25_ENABLE		BIT(31)
> +#define  EFUSE_SELECT_MASK		0x0300
> +#define  EFUSE_WIFI_SELECT		0x0000
> +#define  EFUSE_BT0_SELECT		0x0100
> +#define  EFUSE_BT1_SELECT		0x0200
> +#define  EFUSE_BT2_SELECT		0x0300
> +
> +#define  EFUSE_ACCESS_ENABLE		0x69	/* RTL8723 only */
> +#define  EFUSE_ACCESS_DISABLE		0x00	/* RTL8723 only */
> +
> +#define REG_PWR_DATA			0x0038
> +#define REG_CAL_TIMER			0x003c
> +#define REG_ACLK_MON			0x003e
> +#define REG_GPIO_MUXCFG			0x0040
> +#define REG_GPIO_IO_SEL			0x0042
> +#define REG_MAC_PINMUX_CFG		0x0043
> +#define REG_GPIO_PIN_CTRL		0x0044
> +#define REG_GPIO_INTM			0x0048
> +#define REG_LEDCFG0			0x004c
> +#define REG_LEDCFG1			0x004d
> +#define REG_LEDCFG2			0x004e
> +#define  LEDCFG2_DPDT_SELECT		BIT(7)
> +#define REG_LEDCFG3			0x004f
> +#define REG_LEDCFG			REG_LEDCFG2
> +#define REG_FSIMR			0x0050
> +#define REG_FSISR			0x0054
> +#define REG_HSIMR			0x0058
> +#define REG_HSISR			0x005c
> +/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */
> +#define REG_GPIO_PIN_CTRL_2		0x0060
> +/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */
> +#define REG_GPIO_IO_SEL_2		0x0062
> +
> +/*  RTL8723 only WIFI/BT/GPS Multi-Function control source. */
> +#define REG_MULTI_FUNC_CTRL		0x0068
> +
> +#define  MULTI_FN_WIFI_HW_PWRDOWN_EN	BIT(0)	/* Enable GPIO[9] as WiFi HW
> +						   powerdown source */
> +#define  MULTI_FN_WIFI_HW_PWRDOWN_SL	BIT(1)	/* WiFi HW powerdown polarity
> +						   control */
> +#define  MULTI_WIFI_FUNC_EN		BIT(2)	/* WiFi function enable */
> +
> +#define  MULTI_WIFI_HW_ROF_EN		BIT(3)	/* Enable GPIO[9] as WiFi RF HW
> +						   powerdown source */
> +#define  MULTI_BT_HW_PWRDOWN_EN		BIT(16)	/* Enable GPIO[11] as BT HW
> +						   powerdown source */
> +#define  MULTI_BT_HW_PWRDOWN_SL		BIT(17)	/* BT HW powerdown polarity
> +						   control */
> +#define  MULTI_BT_FUNC_EN		BIT(18)	/* BT function enable */
> +#define  MULTI_BT_HW_ROF_EN		BIT(19)	/* Enable GPIO[11] as BT/GPS
> +						   RF HW powerdown source */
> +#define  MULTI_GPS_HW_PWRDOWN_EN	BIT(20)	/* Enable GPIO[10] as GPS HW
> +						   powerdown source */
> +#define  MULTI_GPS_HW_PWRDOWN_SL	BIT(21)	/* GPS HW powerdown polarity
> +						   control */
> +#define  MULTI_GPS_FUNC_EN		BIT(22)	/* GPS function enable */
> +
> +#define REG_MCU_FW_DL			0x0080
> +#define  MCU_FW_DL_ENABLE		BIT(0)
> +#define  MCU_FW_DL_READY		BIT(1)
> +#define  MCU_FW_DL_CSUM_REPORT		BIT(2)
> +#define  MCU_MAC_INIT_READY		BIT(3)
> +#define  MCU_BB_INIT_READY		BIT(4)
> +#define  MCU_RF_INIT_READY		BIT(5)
> +#define  MCU_WINT_INIT_READY		BIT(6)
> +#define  MCU_FW_RAM_SEL			BIT(7)	/* 1: RAM, 0:ROM */
> +#define  MCU_CP_RESET			BIT(23)
> +
> +#define REG_HMBOX_EXT_0			0x0088
> +#define REG_HMBOX_EXT_1			0x008a
> +#define REG_HMBOX_EXT_2			0x008c
> +#define REG_HMBOX_EXT_3			0x008e
> +/*  Host suspend counter on FPGA platform */
> +#define REG_HOST_SUSP_CNT		0x00bc
> +/*  Efuse access protection for RTL8723 */
> +#define REG_EFUSE_ACCESS		0x00cf
> +#define REG_BIST_SCAN			0x00d0
> +#define REG_BIST_RPT			0x00d4
> +#define REG_BIST_ROM_RPT		0x00d8
> +#define REG_USB_SIE_INTF		0x00e0
> +#define REG_PCIE_MIO_INTF		0x00e4
> +#define REG_PCIE_MIO_INTD		0x00e8
> +#define REG_HPON_FSM			0x00ec
> +#define  HPON_FSM_BONDING_MASK		(BIT(22) | BIT(23))
> +#define  HPON_FSM_BONDING_1T2R		BIT(22)
> +#define REG_SYS_CFG			0x00f0
> +#define  SYS_CFG_XCLK_VLD		BIT(0)
> +#define  SYS_CFG_ACLK_VLD		BIT(1)
> +#define  SYS_CFG_UCLK_VLD		BIT(2)
> +#define  SYS_CFG_PCLK_VLD		BIT(3)
> +#define  SYS_CFG_PCIRSTB		BIT(4)
> +#define  SYS_CFG_V15_VLD		BIT(5)
> +#define  SYS_CFG_TRP_B15V_EN		BIT(7)
> +#define  SYS_CFG_SIC_IDLE		BIT(8)
> +#define  SYS_CFG_BD_MAC2		BIT(9)
> +#define  SYS_CFG_BD_MAC1		BIT(10)
> +#define  SYS_CFG_IC_MACPHY_MODE		BIT(11)
> +#define  SYS_CFG_CHIP_VER		(BIT(12) | BIT(13) | BIT(14) | BIT(15))
> +#define  SYS_CFG_BT_FUNC		BIT(16)
> +#define  SYS_CFG_VENDOR_ID		BIT(19)
> +#define  SYS_CFG_PAD_HWPD_IDN		BIT(22)
> +#define  SYS_CFG_TRP_VAUX_EN		BIT(23)
> +#define  SYS_CFG_TRP_BT_EN		BIT(24)
> +#define  SYS_CFG_BD_PKG_SEL		BIT(25)
> +#define  SYS_CFG_BD_HCI_SEL		BIT(26)
> +#define  SYS_CFG_TYPE_ID		BIT(27)
> +#define  SYS_CFG_RTL_ID			BIT(23) /*  TestChip ID,
> +						    1:Test(RLE); 0:MP(RL) */
> +#define  SYS_CFG_SPS_SEL		BIT(24) /*  1:LDO regulator mode;
> +						    0:Switching regulator mode*/
> +#define  SYS_CFG_CHIP_VERSION_MASK	0xf000	/* Bit 12 - 15 */
> +#define  SYS_CFG_CHIP_VERSION_SHIFT	12
> +
> +#define REG_GPIO_OUTSTS			0x00f4	/*  For RTL8723 only. */
> +#define  GPIO_EFS_HCI_SEL		(BIT(0) | BIT(1))
> +#define  GPIO_PAD_HCI_SEL		(BIT(2) | BIT(3))
> +#define  GPIO_HCI_SEL			(BIT(4) | BIT(5))
> +#define  GPIO_PKG_SEL_HCI		BIT(6)
> +#define  GPIO_FEN_GPS			BIT(7)
> +#define  GPIO_FEN_BT			BIT(8)
> +#define  GPIO_FEN_WL			BIT(9)
> +#define  GPIO_FEN_PCI			BIT(10)
> +#define  GPIO_FEN_USB			BIT(11)
> +#define  GPIO_BTRF_HWPDN_N		BIT(12)
> +#define  GPIO_WLRF_HWPDN_N		BIT(13)
> +#define  GPIO_PDN_BT_N			BIT(14)
> +#define  GPIO_PDN_GPS_N			BIT(15)
> +#define  GPIO_BT_CTL_HWPDN		BIT(16)
> +#define  GPIO_GPS_CTL_HWPDN		BIT(17)
> +#define  GPIO_PPHY_SUSB			BIT(20)
> +#define  GPIO_UPHY_SUSB			BIT(21)
> +#define  GPIO_PCI_SUSEN			BIT(22)
> +#define  GPIO_USB_SUSEN			BIT(23)
> +#define  GPIO_RF_RL_ID			(BIT(31) | BIT(30) | BIT(29) | BIT(28))
> +
> +/* 0x0100 ~ 0x01FF	MACTOP General Configuration */
> +#define REG_CR				0x0100
> +#define  CR_HCI_TXDMA_ENABLE		BIT(0)
> +#define  CR_HCI_RXDMA_ENABLE		BIT(1)
> +#define  CR_TXDMA_ENABLE		BIT(2)
> +#define  CR_RXDMA_ENABLE		BIT(3)
> +#define  CR_PROTOCOL_ENABLE		BIT(4)
> +#define  CR_SCHEDULE_ENABLE		BIT(5)
> +#define  CR_MAC_TX_ENABLE		BIT(6)
> +#define  CR_MAC_RX_ENABLE		BIT(7)
> +#define  CR_SW_BEACON_ENABLE		BIT(8)
> +#define  CR_SECURITY_ENABLE		BIT(9)
> +#define  CR_CALTIMER_ENABLE		BIT(10)
> +
> +/* Media Status Register */
> +#define REG_MSR				0x0102
> +#define  MSR_LINKTYPE_MASK		0x3
> +#define  MSR_LINKTYPE_NONE		0x0
> +#define  MSR_LINKTYPE_ADHOC		0x1
> +#define  MSR_LINKTYPE_STATION		0x2
> +#define  MSR_LINKTYPE_AP		0x3
> +
> +#define REG_PBP				0x0104
> +#define  PBP_PAGE_SIZE_RX_SHIFT		0
> +#define  PBP_PAGE_SIZE_TX_SHIFT		4
> +#define  PBP_PAGE_SIZE_64		0x0
> +#define  PBP_PAGE_SIZE_128		0x1
> +#define  PBP_PAGE_SIZE_256		0x2
> +#define  PBP_PAGE_SIZE_512		0x3
> +#define  PBP_PAGE_SIZE_1024		0x4
> +
> +#define REG_TRXDMA_CTRL			0x010c
> +#define  TRXDMA_CTRL_VOQ_SHIFT		4
> +#define  TRXDMA_CTRL_VIQ_SHIFT		6
> +#define  TRXDMA_CTRL_BEQ_SHIFT		8
> +#define  TRXDMA_CTRL_BKQ_SHIFT		10
> +#define  TRXDMA_CTRL_MGQ_SHIFT		12
> +#define  TRXDMA_CTRL_HIQ_SHIFT		14
> +#define  TRXDMA_QUEUE_LOW		1
> +#define  TRXDMA_QUEUE_NORMAL		2
> +#define  TRXDMA_QUEUE_HIGH		3
> +
> +#define REG_TRXFF_BNDY			0x0114
> +#define REG_TRXFF_STATUS		0x0118
> +#define REG_RXFF_PTR			0x011c
> +#define REG_HIMR			0x0120
> +#define REG_HISR			0x0124
> +#define REG_HIMRE			0x0128
> +#define REG_HISRE			0x012c
> +#define REG_CPWM			0x012f
> +#define REG_FWIMR			0x0130
> +#define REG_FWISR			0x0134
> +#define REG_PKTBUF_DBG_CTRL		0x0140
> +#define REG_PKTBUF_DBG_DATA_L		0x0144
> +#define REG_PKTBUF_DBG_DATA_H		0x0148
> +
> +#define REG_TC0_CTRL			0x0150
> +#define REG_TC1_CTRL			0x0154
> +#define REG_TC2_CTRL			0x0158
> +#define REG_TC3_CTRL			0x015c
> +#define REG_TC4_CTRL			0x0160
> +#define REG_TCUNIT_BASE			0x0164
> +#define REG_MBIST_START			0x0174
> +#define REG_MBIST_DONE			0x0178
> +#define REG_MBIST_FAIL			0x017c
> +#define REG_C2HEVT_MSG_NORMAL		0x01a0
> +#define REG_C2HEVT_CLEAR		0x01af
> +#define REG_C2HEVT_MSG_TEST		0x01b8
> +#define REG_MCUTST_1			0x01c0
> +#define REG_FMTHR			0x01c8
> +#define REG_HMTFR			0x01cc
> +#define REG_HMBOX_0			0x01d0
> +#define REG_HMBOX_1			0x01d4
> +#define REG_HMBOX_2			0x01d8
> +#define REG_HMBOX_3			0x01dc
> +
> +#define REG_LLT_INIT			0x01e0
> +#define  LLT_OP_INACTIVE		0x0
> +#define  LLT_OP_WRITE			(0x1 << 30)
> +#define  LLT_OP_READ			(0x2 << 30)
> +#define  LLT_OP_MASK			(0x3 << 30)
> +
> +#define REG_BB_ACCEESS_CTRL		0x01e8
> +#define REG_BB_ACCESS_DATA		0x01ec
> +
> +/* 0x0200 ~ 0x027F	TXDMA Configuration */
> +#define REG_RQPN			0x0200
> +#define  RQPN_HI_PQ_SHIFT		0
> +#define  RQPN_LO_PQ_SHIFT		8
> +#define  RQPN_NORM_PQ_SHIFT		16
> +#define  RQPN_LOAD			BIT(31)
> +
> +#define REG_FIFOPAGE			0x0204
> +#define REG_TDECTRL			0x0208
> +#define REG_TXDMA_OFFSET_CHK		0x020c
> +#define REG_TXDMA_STATUS		0x0210
> +#define REG_RQPN_NPQ			0x0214
> +
> +/* 0x0280 ~ 0x02FF	RXDMA Configuration */
> +#define REG_RXDMA_AGG_PG_TH		0x0280
> +#define REG_RXPKT_NUM			0x0284
> +#define REG_RXDMA_STATUS		0x0288
> +
> +#define REG_RF_BB_CMD_ADDR		0x02c0
> +#define REG_RF_BB_CMD_DATA		0x02c4
> +
> +/*  spec version 11 */
> +/* 0x0400 ~ 0x047F	Protocol Configuration */
> +#define REG_VOQ_INFORMATION		0x0400
> +#define REG_VIQ_INFORMATION		0x0404
> +#define REG_BEQ_INFORMATION		0x0408
> +#define REG_BKQ_INFORMATION		0x040c
> +#define REG_MGQ_INFORMATION		0x0410
> +#define REG_HGQ_INFORMATION		0x0414
> +#define REG_BCNQ_INFORMATION		0x0418
> +
> +#define REG_CPU_MGQ_INFORMATION		0x041c
> +#define REG_FWHW_TXQ_CTRL		0x0420
> +#define  FWHW_TXQ_CTRL_AMPDU_RETRY	BIT(7)
> +#define  FWHW_TXQ_CTRL_XMIT_MGMT_ACK	BIT(12)
> +
> +#define REG_HWSEQ_CTRL			0x0423
> +#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
> +#define REG_TXPKTBUF_MGQ_BDNY		0x0425
> +#define REG_LIFETIME_EN			0x0426
> +#define REG_MULTI_BCNQ_OFFSET		0x0427
> +
> +#define REG_SPEC_SIFS			0x0428
> +#define  SPEC_SIFS_CCK_MASK		0x00ff
> +#define  SPEC_SIFS_CCK_SHIFT		0
> +#define  SPEC_SIFS_OFDM_MASK		0xff00
> +#define  SPEC_SIFS_OFDM_SHIFT		8
> +
> +#define REG_RETRY_LIMIT			0x042a
> +#define  RETRY_LIMIT_LONG_SHIFT		0
> +#define  RETRY_LIMIT_LONG_MASK		0x003f
> +#define  RETRY_LIMIT_SHORT_SHIFT	8
> +#define  RETRY_LIMIT_SHORT_MASK		0x3f00
> +
> +#define REG_DARFRC			0x0430
> +#define REG_RARFRC			0x0438
> +#define REG_RESPONSE_RATE_SET		0x0440
> +#define  RESPONSE_RATE_BITMAP_ALL	0xfffff
> +#define  RESPONSE_RATE_RRSR_CCK_ONLY_1M	0xffff1
> +#define  RSR_1M				BIT(0)
> +#define  RSR_2M				BIT(1)
> +#define  RSR_5_5M			BIT(2)
> +#define  RSR_11M			BIT(3)
> +#define  RSR_6M				BIT(4)
> +#define  RSR_9M				BIT(5)
> +#define  RSR_12M			BIT(6)
> +#define  RSR_18M			BIT(7)
> +#define  RSR_24M			BIT(8)
> +#define  RSR_36M			BIT(9)
> +#define  RSR_48M			BIT(10)
> +#define  RSR_54M			BIT(11)
> +#define  RSR_MCS0			BIT(12)
> +#define  RSR_MCS1			BIT(13)
> +#define  RSR_MCS2			BIT(14)
> +#define  RSR_MCS3			BIT(15)
> +#define  RSR_MCS4			BIT(16)
> +#define  RSR_MCS5			BIT(17)
> +#define  RSR_MCS6			BIT(18)
> +#define  RSR_MCS7			BIT(19)
> +#define  RSR_RSC_LOWER_SUB_CHANNEL	BIT(21)	/* 0x200000 */
> +#define  RSR_RSC_UPPER_SUB_CHANNEL	BIT(22)	/* 0x400000 */
> +#define  RSR_RSC_BANDWIDTH_40M		(RSR_RSC_UPPER_SUB_CHANNEL | \
> +					 RSR_RSC_LOWER_SUB_CHANNEL)
> +#define  RSR_ACK_SHORT_PREAMBLE		BIT(23)
> +
> +#define REG_ARFR0			0x0444
> +#define REG_ARFR1			0x0448
> +#define REG_ARFR2			0x044c
> +#define REG_ARFR3			0x0450
> +#define REG_AGGLEN_LMT			0x0458
> +#define REG_AMPDU_MIN_SPACE		0x045c
> +#define REG_TXPKTBUF_WMAC_LBK_BF_HD	0x045d
> +#define REG_FAST_EDCA_CTRL		0x0460
> +#define REG_RD_RESP_PKT_TH		0x0463
> +#define REG_INIRTS_RATE_SEL		0x0480
> +#define REG_INIDATA_RATE_SEL		0x0484
> +
> +#define REG_POWER_STATUS		0x04a4
> +#define REG_POWER_STAGE1		0x04b4
> +#define REG_POWER_STAGE2		0x04b8
> +#define REG_PKT_VO_VI_LIFE_TIME		0x04c0
> +#define REG_PKT_BE_BK_LIFE_TIME		0x04c2
> +#define REG_STBC_SETTING		0x04c4
> +#define REG_PROT_MODE_CTRL		0x04c8
> +#define REG_MAX_AGGR_NUM		0x04ca
> +#define REG_RTS_MAX_AGGR_NUM		0x04cb
> +#define REG_BAR_MODE_CTRL		0x04cc
> +#define REG_RA_TRY_RATE_AGG_LMT		0x04cf
> +#define REG_NQOS_SEQ			0x04dc
> +#define REG_QOS_SEQ			0x04de
> +#define REG_NEED_CPU_HANDLE		0x04e0
> +#define REG_PKT_LOSE_RPT		0x04e1
> +#define REG_PTCL_ERR_STATUS		0x04e2
> +#define REG_DUMMY			0x04fc
> +
> +/* 0x0500 ~ 0x05FF	EDCA Configuration */
> +#define REG_EDCA_VO_PARAM		0x0500
> +#define REG_EDCA_VI_PARAM		0x0504
> +#define REG_EDCA_BE_PARAM		0x0508
> +#define REG_EDCA_BK_PARAM		0x050c
> +#define  EDCA_PARAM_ECW_MIN_SHIFT	8
> +#define  EDCA_PARAM_ECW_MAX_SHIFT	12
> +#define  EDCA_PARAM_TXOP_SHIFT		16
> +#define REG_BEACON_TCFG			0x0510
> +#define REG_PIFS			0x0512
> +#define REG_RDG_PIFS			0x0513
> +#define REG_SIFS_CCK			0x0514
> +#define REG_SIFS_OFDM			0x0516
> +#define REG_TSFTR_SYN_OFFSET		0x0518
> +#define REG_AGGR_BREAK_TIME		0x051a
> +#define REG_SLOT			0x051b
> +#define REG_TX_PTCL_CTRL		0x0520
> +#define REG_TXPAUSE			0x0522
> +#define REG_DIS_TXREQ_CLR		0x0523
> +#define REG_RD_CTRL			0x0524
> +#define REG_TBTT_PROHIBIT		0x0540
> +#define REG_RD_NAV_NXT			0x0544
> +#define REG_NAV_PROT_LEN		0x0546
> +
> +#define REG_BEACON_CTRL			0x0550
> +#define REG_BEACON_CTRL_1		0x0551
> +#define  BEACON_ATIM			BIT(0)
> +#define  BEACON_CTRL_MBSSID		BIT(1)
> +#define  BEACON_CTRL_TX_BEACON_RPT	BIT(2)
> +#define  BEACON_FUNCTION_ENABLE		BIT(3)
> +#define  BEACON_DISABLE_TSF_UPDATE	BIT(4)
> +
> +#define REG_MBID_NUM			0x0552
> +#define REG_DUAL_TSF_RST		0x0553
> +#define  DUAL_TSF_RESET_TSF0		BIT(0)
> +#define  DUAL_TSF_RESET_TSF1		BIT(1)
> +#define  DUAL_TSF_RESET_P2P		BIT(4)
> +#define  DUAL_TSF_TX_OK			BIT(5)
> +
> +/*  The same as REG_MBSSID_BCN_SPACE */
> +#define REG_BCN_INTERVAL		0x0554
> +#define REG_MBSSID_BCN_SPACE		0x0554
> +
> +#define REG_DRIVER_EARLY_INT		0x0558
> +#define  DRIVER_EARLY_INT_TIME		5
> +
> +#define REG_BEACON_DMA_TIME		0x0559
> +#define  BEACON_DMA_ATIME_INT_TIME	2
> +
> +#define REG_ATIMWND			0x055a
> +#define REG_BCN_MAX_ERR			0x055d
> +#define REG_RXTSF_OFFSET_CCK		0x055e
> +#define REG_RXTSF_OFFSET_OFDM		0x055f
> +#define REG_TSFTR			0x0560
> +#define REG_TSFTR1			0x0568
> +#define REG_INIT_TSFTR			0x0564
> +#define REG_ATIMWND_1			0x0570
> +#define REG_PSTIMER			0x0580
> +#define REG_TIMER0			0x0584
> +#define REG_TIMER1			0x0588
> +#define REG_ACM_HW_CTRL			0x05c0
> +#define  ACM_HW_CTRL_BK			BIT(0)
> +#define  ACM_HW_CTRL_BE			BIT(1)
> +#define  ACM_HW_CTRL_VI			BIT(2)
> +#define  ACM_HW_CTRL_VO			BIT(3)
> +#define REG_ACM_RST_CTRL		0x05c1
> +#define REG_ACMAVG			0x05c2
> +#define REG_VO_ADMTIME			0x05c4
> +#define REG_VI_ADMTIME			0x05c6
> +#define REG_BE_ADMTIME			0x05c8
> +#define REG_EDCA_RANDOM_GEN		0x05cc
> +#define REG_SCH_TXCMD			0x05d0
> +
> +/* define REG_FW_TSF_SYNC_CNT		0x04a0 */
> +#define REG_FW_RESET_TSF_CNT_1		0x05fc
> +#define REG_FW_RESET_TSF_CNT_0		0x05fd
> +#define REG_FW_BCN_DIS_CNT		0x05fe
> +
> +/* 0x0600 ~ 0x07FF  WMAC Configuration */
> +#define REG_APSD_CTRL			0x0600
> +#define  APSD_CTRL_OFF			BIT(6)
> +#define  APSD_CTRL_OFF_STATUS		BIT(7)
> +#define REG_BW_OPMODE			0x0603
> +#define  BW_OPMODE_20MHZ		BIT(2)
> +#define  BW_OPMODE_5G			BIT(1)
> +#define  BW_OPMODE_11J			BIT(0)
> +
> +#define REG_TCR				0x0604
> +
> +/* Receive Configuration Register */
> +#define REG_RCR				0x0608
> +#define  RCR_ACCEPT_AP			BIT(0)  /* Accept all unicast packet */
> +#define  RCR_ACCEPT_PHYS_MATCH		BIT(1)  /* Accept phys match packet */
> +#define  RCR_ACCEPT_MCAST		BIT(2)
> +#define  RCR_ACCEPT_BCAST		BIT(3)
> +#define  RCR_ACCEPT_ADDR3		BIT(4)  /* Accept address 3 match
> +						 packet */
> +#define  RCR_ACCEPT_PM			BIT(5)  /* Accept power management
> +						 packet */
> +#define  RCR_CHECK_BSSID_MATCH		BIT(6)  /* Accept BSSID match packet */
> +#define  RCR_CHECK_BSSID_BEACON		BIT(7)  /* Accept BSSID match packet
> +						 (Rx beacon, probe rsp) */
> +#define  RCR_ACCEPT_CRC32		BIT(8)  /* Accept CRC32 error packet */
> +#define  RCR_ACCEPT_ICV			BIT(9)  /* Accept ICV error packet */
> +#define  RCR_ACCEPT_DATA_FRAME		BIT(11)
> +#define  RCR_ACCEPT_CTRL_FRAME		BIT(12)
> +#define  RCR_ACCEPT_MGMT_FRAME		BIT(13)
> +#define  RCR_HTC_LOC_CTRL		BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */
> +#define  RCR_MFBEN			BIT(22)
> +#define  RCR_LSIGEN			BIT(23)
> +#define  RCR_MULTI_BSSID_ENABLE		BIT(24) /* Enable Multiple BssId */
> +#define  RCR_ACCEPT_BA_SSN		BIT(27) /* Accept BA SSN */
> +#define  RCR_APPEND_PHYSTAT		BIT(28)
> +#define  RCR_APPEND_ICV			BIT(29)
> +#define  RCR_APPEND_MIC			BIT(30)
> +#define  RCR_APPEND_FCS			BIT(31) /* WMAC append FCS after */
> +
> +#define REG_RX_PKT_LIMIT		0x060c
> +#define REG_RX_DLK_TIME			0x060d
> +#define REG_RX_DRVINFO_SZ		0x060f
> +
> +#define REG_MACID			0x0610
> +#define REG_BSSID			0x0618
> +#define REG_MAR				0x0620
> +#define REG_MBIDCAMCFG			0x0628
> +
> +#define REG_USTIME_EDCA			0x0638
> +#define REG_MAC_SPEC_SIFS		0x063a
> +
> +/*  20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
> +	/*  [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
> +#define REG_R2T_SIFS			0x063c
> +	/*  [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
> +#define REG_T2T_SIFS			0x063e
> +#define REG_ACKTO			0x0640
> +#define REG_CTS2TO			0x0641
> +#define REG_EIFS			0x0642
> +
> +/* WMA, BA, CCX */
> +#define REG_NAV_CTRL			0x0650
> +/* In units of 128us */
> +#define REG_NAV_UPPER			0x0652
> +#define  NAV_UPPER_UNIT			128
> +
> +#define REG_BACAMCMD			0x0654
> +#define REG_BACAMCONTENT		0x0658
> +#define REG_LBDLY			0x0660
> +#define REG_FWDLY			0x0661
> +#define REG_RXERR_RPT			0x0664
> +#define REG_WMAC_TRXPTCL_CTL		0x0668
> +
> +/*  Security */
> +#define REG_CAM_CMD			0x0670
> +#define  CAM_CMD_POLLING		BIT(31)
> +#define  CAM_CMD_WRITE			BIT(16)
> +#define  CAM_CMD_KEY_SHIFT		3
> +#define REG_CAM_WRITE			0x0674
> +#define  CAM_WRITE_VALID		BIT(15)
> +#define REG_CAM_READ			0x0678
> +#define REG_CAM_DEBUG			0x067c
> +#define REG_SECURITY_CFG		0x0680
> +#define  SEC_CFG_TX_USE_DEFKEY		BIT(0)
> +#define  SEC_CFG_RX_USE_DEFKEY		BIT(1)
> +#define  SEC_CFG_TX_SEC_ENABLE		BIT(2)
> +#define  SEC_CFG_RX_SEC_ENABLE		BIT(3)
> +#define  SEC_CFG_SKBYA2			BIT(4)
> +#define  SEC_CFG_NO_SKMC		BIT(5)
> +#define  SEC_CFG_TXBC_USE_DEFKEY	BIT(6)
> +#define  SEC_CFG_RXBC_USE_DEFKEY	BIT(7)
> +
> +/*  Power */
> +#define REG_WOW_CTRL			0x0690
> +#define REG_PSSTATUS			0x0691
> +#define REG_PS_RX_INFO			0x0692
> +#define REG_LPNAV_CTRL			0x0694
> +#define REG_WKFMCAM_CMD			0x0698
> +#define REG_WKFMCAM_RWD			0x069c
> +#define REG_RXFLTMAP0			0x06a0
> +#define REG_RXFLTMAP1			0x06a2
> +#define REG_RXFLTMAP2			0x06a4
> +#define REG_BCN_PSR_RPT			0x06a8
> +#define REG_CALB32K_CTRL		0x06ac
> +#define REG_PKT_MON_CTRL		0x06b4
> +#define REG_BT_COEX_TABLE		0x06c0
> +#define REG_WMAC_RESP_TXINFO		0x06d8
> +
> +#define REG_MACID1			0x0700
> +#define REG_BSSID1			0x0708
> +
> +#define REG_FPGA0_RF_MODE		0x0800
> +#define  FPGA_RF_MODE			BIT(0)
> +#define  FPGA_RF_MODE_JAPAN		BIT(1)
> +#define  FPGA_RF_MODE_CCK		BIT(24)
> +#define  FPGA_RF_MODE_OFDM		BIT(25)
> +
> +#define REG_FPGA0_TX_INFO		0x0804
> +#define REG_FPGA0_PSD_FUNC		0x0808
> +#define REG_FPGA0_TX_GAIN		0x080c
> +#define REG_FPGA0_RF_TIMING1		0x0810
> +#define REG_FPGA0_RF_TIMING2		0x0814
> +#define REG_FPGA0_POWER_SAVE		0x0818
> +#define  FPGA0_PS_LOWER_CHANNEL		BIT(26)
> +#define  FPGA0_PS_UPPER_CHANNEL		BIT(27)
> +
> +#define REG_FPGA0_XA_HSSI_PARM1		0x0820	/* RF 3 wire register */
> +#define  FPGA0_HSSI_PARM1_PI		BIT(8)
> +#define REG_FPGA0_XA_HSSI_PARM2		0x0824
> +#define REG_FPGA0_XB_HSSI_PARM1		0x0828
> +#define REG_FPGA0_XB_HSSI_PARM2		0x082c
> +#define  FPGA0_HSSI_3WIRE_DATA_LEN	0x800
> +#define  FPGA0_HSSI_3WIRE_ADDR_LEN	0x400
> +#define  FPGA0_HSSI_PARM2_ADDR_SHIFT	23
> +#define  FPGA0_HSSI_PARM2_ADDR_MASK	0x7f800000	/* 0xff << 23 */
> +#define  FPGA0_HSSI_PARM2_CCK_HIGH_PWR	BIT(9)
> +#define  FPGA0_HSSI_PARM2_EDGE_READ	BIT(31)
> +
> +#define REG_TX_AGC_B_RATE18_06		0x0830
> +#define REG_TX_AGC_B_RATE54_24		0x0834
> +#define REG_TX_AGC_B_CCK1_55_MCS32	0x0838
> +#define REG_TX_AGC_B_MCS03_MCS00	0x083c
> +
> +#define REG_FPGA0_XA_LSSI_PARM		0x0840
> +#define REG_FPGA0_XB_LSSI_PARM		0x0844
> +#define  FPGA0_LSSI_PARM_ADDR_SHIFT	20
> +#define  FPGA0_LSSI_PARM_ADDR_MASK	0x0ff00000
> +#define  FPGA0_LSSI_PARM_DATA_MASK	0x000fffff
> +
> +#define REG_TX_AGC_B_MCS07_MCS04	0x0848
> +#define REG_TX_AGC_B_MCS11_MCS08	0x084c
> +
> +#define REG_FPGA0_XCD_SWITCH_CTRL	0x085c
> +
> +#define REG_FPGA0_XA_RF_INT_OE		0x0860	/* RF Channel switch */
> +#define REG_FPGA0_XB_RF_INT_OE		0x0864
> +#define  FPGA0_INT_OE_ANTENNA_AB_OPEN	0x000
> +#define  FPGA0_INT_OE_ANTENNA_A		0x100
> +#define  FPGA0_INT_OE_ANTENNA_B		0x200
> +#define  FPGA0_INT_OE_ANTENNA_MASK	0x300
> +
> +#define REG_TX_AGC_B_MCS15_MCS12	0x0868
> +#define REG_TX_AGC_B_CCK11_A_CCK2_11	0x086c
> +
> +#define REG_FPGA0_XAB_RF_SW_CTRL	0x0870
> +#define REG_FPGA0_XA_RF_SW_CTRL		0x0870	/* 16 bit */
> +#define REG_FPGA0_XB_RF_SW_CTRL		0x0872	/* 16 bit */
> +#define REG_FPGA0_XCD_RF_SW_CTRL	0x0874
> +#define REG_FPGA0_XC_RF_SW_CTRL		0x0874	/* 16 bit */
> +#define REG_FPGA0_XD_RF_SW_CTRL		0x0876	/* 16 bit */
> +#define  FPGA0_RF_3WIRE_DATA		BIT(0)
> +#define  FPGA0_RF_3WIRE_CLOC		BIT(1)
> +#define  FPGA0_RF_3WIRE_LOAD		BIT(2)
> +#define  FPGA0_RF_3WIRE_RW		BIT(3)
> +#define  FPGA0_RF_3WIRE_MASK		0xf
> +#define  FPGA0_RF_RFENV			BIT(4)
> +#define  FPGA0_RF_TRSW			BIT(5)	/* Useless now */
> +#define  FPGA0_RF_TRSWB			BIT(6)
> +#define  FPGA0_RF_ANTSW			BIT(8)
> +#define  FPGA0_RF_ANTSWB		BIT(9)
> +#define  FPGA0_RF_PAPE			BIT(10)
> +#define  FPGA0_RF_PAPE5G		BIT(11)
> +#define  FPGA0_RF_BD_CTRL_SHIFT		16
> +
> +#define REG_FPGA0_XAB_RF_PARM		0x0878	/* Antenna select path in ODM */
> +#define REG_FPGA0_XA_RF_PARM		0x0878	/* 16 bit */
> +#define REG_FPGA0_XB_RF_PARM		0x087a	/* 16 bit */
> +#define REG_FPGA0_XCD_RF_PARM		0x087c
> +#define REG_FPGA0_XC_RF_PARM		0x087c	/* 16 bit */
> +#define REG_FPGA0_XD_RF_PARM		0x087e	/* 16 bit */
> +#define  FPGA0_RF_PARM_RFA_ENABLE	BIT(1)
> +#define  FPGA0_RF_PARM_RFB_ENABLE	BIT(17)
> +#define  FPGA0_RF_PARM_CLK_GATE		BIT(31)
> +
> +#define REG_FPGA0_ANALOG1		0x0880
> +#define REG_FPGA0_ANALOG2		0x0884
> +#define  FPGA0_ANALOG2_20MHZ		BIT(10)
> +#define REG_FPGA0_ANALOG3		0x0888
> +#define REG_FPGA0_ANALOG4		0x088c
> +
> +#define REG_FPGA0_XA_LSSI_READBACK	0x08a0	/* Tranceiver LSSI Readback */
> +#define REG_FPGA0_XB_LSSI_READBACK	0x08a4
> +#define REG_HSPI_XA_READBACK		0x08b8	/* Transceiver A HSPI read */
> +#define REG_HSPI_XB_READBACK		0x08bc	/* Transceiver B HSPI read */
> +
> +#define REG_FPGA1_RF_MODE		0x0900
> +
> +#define REG_FPGA1_TX_INFO		0x090c
> +
> +#define REG_CCK0_SYSTEM			0x0a00
> +#define  CCK0_SIDEBAND			BIT(4)
> +
> +#define REG_CCK0_AFE_SETTING		0x0a04
> +
> +#define REG_CONFIG_ANT_A		0x0b68
> +#define REG_CONFIG_ANT_B		0x0b6c
> +
> +#define REG_OFDM0_TRX_PATH_ENABLE	0x0c04
> +#define OFDM_RF_PATH_RX_MASK		0x0f
> +#define OFDM_RF_PATH_RX_A		BIT(0)
> +#define OFDM_RF_PATH_RX_B		BIT(1)
> +#define OFDM_RF_PATH_RX_C		BIT(2)
> +#define OFDM_RF_PATH_RX_D		BIT(3)
> +#define OFDM_RF_PATH_TX_MASK		0xf0
> +#define OFDM_RF_PATH_TX_A		BIT(4)
> +#define OFDM_RF_PATH_TX_B		BIT(5)
> +#define OFDM_RF_PATH_TX_C		BIT(6)
> +#define OFDM_RF_PATH_TX_D		BIT(7)
> +
> +#define REG_OFDM0_TR_MUX_PAR		0x0c08
> +
> +#define REG_OFDM0_XA_RX_IQ_IMBALANCE	0x0c14
> +#define REG_OFDM0_XB_RX_IQ_IMBALANCE	0x0c1c
> +
> +#define REG_OFDM0_ENERGY_CCA_THRES	0x0c4c
> +
> +#define REG_OFDM0_XA_AGC_CORE1		0x0c50
> +#define REG_OFDM0_XA_AGC_CORE2		0x0c54
> +#define REG_OFDM0_XB_AGC_CORE1		0x0c58
> +#define REG_OFDM0_XB_AGC_CORE2		0x0c5c
> +#define REG_OFDM0_XC_AGC_CORE1		0x0c60
> +#define REG_OFDM0_XC_AGC_CORE2		0x0c64
> +#define REG_OFDM0_XD_AGC_CORE1		0x0c68
> +#define REG_OFDM0_XD_AGC_CORE2		0x0c6c
> +#define  OFDM0_X_AGC_CORE1_IGI_MASK	0x0000007F
> +
> +#define REG_OFDM0_AGC_PARM1		0x0c70
> +
> +#define REG_OFDM0_AGCR_SSI_TABLE	0x0c78
> +
> +#define REG_OFDM0_XA_TX_IQ_IMBALANCE	0x0c80
> +#define REG_OFDM0_XB_TX_IQ_IMBALANCE	0x0c88
> +#define REG_OFDM0_XC_TX_IQ_IMBALANCE	0x0c90
> +#define REG_OFDM0_XD_TX_IQ_IMBALANCE	0x0c98
> +
> +#define REG_OFDM0_XC_TX_AFE		0x0c94
> +#define REG_OFDM0_XD_TX_AFE		0x0c9c
> +
> +#define REG_OFDM0_RX_IQ_EXT_ANTA	0x0ca0
> +
> +#define REG_OFDM1_LSTF			0x0d00
> +#define  OFDM_LSTF_PRIME_CH_LOW		BIT(10)
> +#define  OFDM_LSTF_PRIME_CH_HIGH	BIT(11)
> +#define  OFDM_LSTF_PRIME_CH_MASK	(OFDM_LSTF_PRIME_CH_LOW | \
> +					 OFDM_LSTF_PRIME_CH_HIGH)
> +#define  OFDM_LSTF_CONTINUE_TX		BIT(28)
> +#define  OFDM_LSTF_SINGLE_CARRIER	BIT(29)
> +#define  OFDM_LSTF_SINGLE_TONE		BIT(30)
> +#define  OFDM_LSTF_MASK			0x70000000
> +
> +#define REG_OFDM1_TRX_PATH_ENABLE	0x0d04
> +
> +#define REG_TX_AGC_A_RATE18_06		0x0e00
> +#define REG_TX_AGC_A_RATE54_24		0x0e04
> +#define REG_TX_AGC_A_CCK1_MCS32		0x0e08
> +#define REG_TX_AGC_A_MCS03_MCS00	0x0e10
> +#define REG_TX_AGC_A_MCS07_MCS04	0x0e14
> +#define REG_TX_AGC_A_MCS11_MCS08	0x0e18
> +#define REG_TX_AGC_A_MCS15_MCS12	0x0e1c
> +
> +#define REG_FPGA0_IQK			0x0e28
> +
> +#define REG_TX_IQK_TONE_A		0x0e30
> +#define REG_RX_IQK_TONE_A		0x0e34
> +#define REG_TX_IQK_PI_A			0x0e38
> +#define REG_RX_IQK_PI_A			0x0e3c
> +
> +#define REG_TX_IQK			0x0e40
> +#define REG_RX_IQK			0x0e44
> +#define REG_IQK_AGC_PTS			0x0e48
> +#define REG_IQK_AGC_RSP			0x0e4c
> +#define REG_TX_IQK_TONE_B		0x0e50
> +#define REG_RX_IQK_TONE_B		0x0e54
> +#define REG_TX_IQK_PI_B			0x0e58
> +#define REG_RX_IQK_PI_B			0x0e5c
> +#define REG_IQK_AGC_CONT		0x0e60
> +
> +#define REG_BLUETOOTH			0x0e6c
> +#define REG_RX_WAIT_CCA			0x0e70
> +#define REG_TX_CCK_RFON			0x0e74
> +#define REG_TX_CCK_BBON			0x0e78
> +#define REG_TX_OFDM_RFON		0x0e7c
> +#define REG_TX_OFDM_BBON		0x0e80
> +#define REG_TX_TO_RX			0x0e84
> +#define REG_TX_TO_TX			0x0e88
> +#define REG_RX_CCK			0x0e8c
> +
> +#define REG_TX_POWER_BEFORE_IQK_A	0x0e94
> +#define REG_TX_POWER_AFTER_IQK_A	0x0e9c
> +
> +#define REG_RX_POWER_BEFORE_IQK_A	0x0ea0
> +#define REG_RX_POWER_BEFORE_IQK_A_2	0x0ea4
> +#define REG_RX_POWER_AFTER_IQK_A	0x0ea8
> +#define REG_RX_POWER_AFTER_IQK_A_2	0x0eac
> +
> +#define REG_TX_POWER_BEFORE_IQK_B	0x0eb4
> +#define REG_TX_POWER_AFTER_IQK_B	0x0ebc
> +
> +#define REG_RX_POWER_BEFORE_IQK_B	0x0ec0
> +#define REG_RX_POWER_BEFORE_IQK_B_2	0x0ec4
> +#define REG_RX_POWER_AFTER_IQK_B	0x0ec8
> +#define REG_RX_POWER_AFTER_IQK_B_2	0x0ecc
> +
> +#define REG_RX_OFDM			0x0ed0
> +#define REG_RX_WAIT_RIFS		0x0ed4
> +#define REG_RX_TO_RX			0x0ed8
> +#define REG_STANDBY			0x0edc
> +#define REG_SLEEP			0x0ee0
> +#define REG_PMPD_ANAEN			0x0eec
> +
> +#define REG_FW_START_ADDRESS		0x1000
> +
> +#define REG_USB_INFO			0xfe17
> +#define REG_USB_HIMR			0xfe38
> +#define  USB_HIMR_TIMEOUT2		BIT(31)
> +#define  USB_HIMR_TIMEOUT1		BIT(30)
> +#define  USB_HIMR_PSTIMEOUT		BIT(29)
> +#define  USB_HIMR_GTINT4		BIT(28)
> +#define  USB_HIMR_GTINT3		BIT(27)
> +#define  USB_HIMR_TXBCNERR		BIT(26)
> +#define  USB_HIMR_TXBCNOK		BIT(25)
> +#define  USB_HIMR_TSF_BIT32_TOGGLE	BIT(24)
> +#define  USB_HIMR_BCNDMAINT3		BIT(23)
> +#define  USB_HIMR_BCNDMAINT2		BIT(22)
> +#define  USB_HIMR_BCNDMAINT1		BIT(21)
> +#define  USB_HIMR_BCNDMAINT0		BIT(20)
> +#define  USB_HIMR_BCNDOK3		BIT(19)
> +#define  USB_HIMR_BCNDOK2		BIT(18)
> +#define  USB_HIMR_BCNDOK1		BIT(17)
> +#define  USB_HIMR_BCNDOK0		BIT(16)
> +#define  USB_HIMR_HSISR_IND		BIT(15)
> +#define  USB_HIMR_BCNDMAINT_E		BIT(14)
> +/* RSVD	BIT(13) */
> +#define  USB_HIMR_CTW_END		BIT(12)
> +/* RSVD	BIT(11) */
> +#define  USB_HIMR_C2HCMD		BIT(10)
> +#define  USB_HIMR_CPWM2			BIT(9)
> +#define  USB_HIMR_CPWM			BIT(8)
> +#define  USB_HIMR_HIGHDOK		BIT(7)	/*  High Queue DMA OK
> +						    Interrupt */
> +#define  USB_HIMR_MGNTDOK		BIT(6)	/*  Management Queue DMA OK
> +						    Interrupt */
> +#define  USB_HIMR_BKDOK			BIT(5)	/*  AC_BK DMA OK Interrupt */
> +#define  USB_HIMR_BEDOK			BIT(4)	/*  AC_BE DMA OK Interrupt */
> +#define  USB_HIMR_VIDOK			BIT(3)	/*  AC_VI DMA OK Interrupt */
> +#define  USB_HIMR_VODOK			BIT(2)	/*  AC_VO DMA Interrupt */
> +#define  USB_HIMR_RDU			BIT(1)	/*  Receive Descriptor
> +						    Unavailable */
> +#define  USB_HIMR_ROK			BIT(0)	/*  Receive DMA OK Interrupt */
> +
> +#define REG_USB_SPECIAL_OPTION		0xfe55
> +#define REG_USB_DMA_AGG_TO		0xfe5b
> +#define REG_USB_AGG_TO			0xfe5c
> +#define REG_USB_AGG_TH			0xfe5d
> +
> +#define REG_NORMAL_SIE_VID		0xfe60	/* 0xfe60 - 0xfe61 */
> +#define REG_NORMAL_SIE_PID		0xfe62	/* 0xfe62 - 0xfe63 */
> +#define REG_NORMAL_SIE_OPTIONAL		0xfe64
> +#define REG_NORMAL_SIE_EP		0xfe65	/* 0xfe65 - 0xfe67 */
> +#define REG_NORMAL_SIE_EP_TX		0xfe66
> +#define  NORMAL_SIE_EP_TX_HIGH_MASK	0x000f
> +#define  NORMAL_SIE_EP_TX_NORMAL_MASK	0x00f0
> +#define  NORMAL_SIE_EP_TX_LOW_MASK	0x0f00
> +
> +#define REG_NORMAL_SIE_PHY		0xfe68	/* 0xfe68 - 0xfe6b */
> +#define REG_NORMAL_SIE_OPTIONAL2	0xfe6c
> +#define REG_NORMAL_SIE_GPS_EP		0xfe6d	/* RTL8723 only */
> +#define REG_NORMAL_SIE_MAC_ADDR		0xfe70	/* 0xfe70 - 0xfe75 */
> +#define REG_NORMAL_SIE_STRING		0xfe80	/* 0xfe80 - 0xfedf */
> +
> +/* RF6052 registers */
> +#define RF6052_REG_AC			0x00
> +#define RF6052_REG_IQADJ_G1		0x01
> +#define RF6052_REG_IQADJ_G2		0x02
> +#define RF6052_REG_BS_PA_APSET_G1_G4	0x03
> +#define RF6052_REG_BS_PA_APSET_G5_G8	0x04
> +#define RF6052_REG_POW_TRSW		0x05
> +#define RF6052_REG_GAIN_RX		0x06
> +#define RF6052_REG_GAIN_TX		0x07
> +#define RF6052_REG_TXM_IDAC		0x08
> +#define RF6052_REG_IPA_G		0x09
> +#define RF6052_REG_TXBIAS_G		0x0a
> +#define RF6052_REG_TXPA_AG		0x0b
> +#define RF6052_REG_IPA_A		0x0c
> +#define RF6052_REG_TXBIAS_A		0x0d
> +#define RF6052_REG_BS_PA_APSET_G9_G11	0x0e
> +#define RF6052_REG_BS_IQGEN		0x0f
> +#define RF6052_REG_MODE1		0x10
> +#define RF6052_REG_MODE2		0x11
> +#define RF6052_REG_RX_AGC_HP		0x12
> +#define RF6052_REG_TX_AGC		0x13
> +#define RF6052_REG_BIAS			0x14
> +#define RF6052_REG_IPA			0x15
> +#define RF6052_REG_TXBIAS		0x16
> +#define RF6052_REG_POW_ABILITY		0x17
> +#define RF6052_REG_MODE_AG		0x18	/* RF channel and BW switch */
> +#define  MODE_AG_CHANNEL_MASK		0x3ff
> +#define  MODE_AG_CHANNEL_20MHZ		BIT(10)
> +
> +#define RF6052_REG_TOP			0x19
> +#define RF6052_REG_RX_G1		0x1a
> +#define RF6052_REG_RX_G2		0x1b
> +#define RF6052_REG_RX_BB2		0x1c
> +#define RF6052_REG_RX_BB1		0x1d
> +#define RF6052_REG_RCK1			0x1e
> +#define RF6052_REG_RCK2			0x1f
> +#define RF6052_REG_TX_G1		0x20
> +#define RF6052_REG_TX_G2		0x21
> +#define RF6052_REG_TX_G3		0x22
> +#define RF6052_REG_TX_BB1		0x23
> +#define RF6052_REG_T_METER		0x24
> +#define RF6052_REG_SYN_G1		0x25	/* RF TX Power control */
> +#define RF6052_REG_SYN_G2		0x26	/* RF TX Power control */
> +#define RF6052_REG_SYN_G3		0x27	/* RF TX Power control */
> +#define RF6052_REG_SYN_G4		0x28	/* RF TX Power control */
> +#define RF6052_REG_SYN_G5		0x29	/* RF TX Power control */
> +#define RF6052_REG_SYN_G6		0x2a	/* RF TX Power control */
> +#define RF6052_REG_SYN_G7		0x2b	/* RF TX Power control */
> +#define RF6052_REG_SYN_G8		0x2c	/* RF TX Power control */
> +
> +#define RF6052_REG_RCK_OS		0x30	/* RF TX PA control */
> +
> +#define RF6052_REG_TXPA_G1		0x31	/* RF TX PA control */
> +#define RF6052_REG_TXPA_G2		0x32	/* RF TX PA control */
> +#define RF6052_REG_TXPA_G3		0x33	/* RF TX PA control */
>

Some comments that are not part of the review, but may be of interest to 
potential users:

1. The gain settings on the RTL81{88,92}CU parts greatly reduce its usefullnes. 
My Edimax 7811 can only find 1 of my 5 local APs in a scan. It can connect to 
that AP, but achieves less than 10 Mbps for both RX and TX operations. I expect 
to be able to discover better initialization variables, but that may take a while.

2. The driver fails to produce a wireless device on the PowerPC because the 
firmware ready to run bit is never set. I have not seen any reason for this to 
be a big-endian issue, and it may be another pecularity of the USB subsystem on 
that laptop. For example, USB devices that are plugged in at boot time fail, 
even though they work if hot plugged into a running system.

For a new driver written from scratch, it looks pretty good.

Larry


Larry


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30  4:42   ` Larry Finger
@ 2015-08-30 18:41     ` Jes Sorensen
  2015-08-30 21:02       ` Jes Sorensen
                         ` (3 more replies)
  0 siblings, 4 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-08-30 18:41 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, kvalo, johannes

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 08/29/2015 04:18 PM, Jes.Sorensen@redhat.com wrote:
>> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>>
>> This is an alternate driver for a number of Realtek WiFi USB devices,
>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>> It was written from scratch utilizing the Linux mac80211 stack.
>>
>> After spending months cleaning up the vendor provided rtl8723au
>> driver, which comes with it's own 802.11 stack included, I decided to
>> rewrite this driver from the bottom up.
>>
>> Many thanks to Johannes Berg for 802.11 insights and help and Larry
>> Finger for help with the vendor driver.
>>
>> The full git log for the development of this driver can be found here:
>> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>>      branch rtl8723au-mac80211
>>
>> This driver is still under development, but has proven to be very
>> stable for me. It currently supports station mode only. It has support
>> for OFDM and CCK rates, as well as AMPDU. It does lack certain
>> features found in the staging driver, such as power management and
>> 40MHz channel support. In addition it does not support AD-HOC, AP, and
>> monitor mode support at this point.
>>
>> The driver is known to work with the following devices:
>> Lenovo Yoga (rtl8723au)
>> TP-Link TL-WN823N (rtl8192cu)
>> Etekcity 6R (rtl8188cu)
>> Daffodil LAN03 (rtl8188cu)
>> Alfa AWUS036NHR (rtl8188ru)
>>
>> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
>
> I did not realize you were resubmitting this driver so soon. I have
> been accumulating some patches that I was going to send to you in the
> next couple of days. The most important of these are described inline
> below.

Thanks - I already ran it through checkpatch, there is nothing from
checkpatch that needs to be resolved.

>> +
>> +static int rtl8xxxu_debug = 0;
>
> Checkpatch reports:
>
> ERROR: do not initialise statics to 0 or NULL
> #106: FILE: drivers/net/wireless/rtl8xxxu.c:45:
> +static int rtl8xxxu_debug = 0;

I really hate these pointless checkpatch warnings, but I guess I should
just post the 0 in comments to not have to waste time on people
submitting patches for this.

>> +	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02lx bytes):\n",
>> +		 __func__, sizeof(struct rtl8192cu_efuse));
>
> On a 32-bit PowerPC, the above line outputs the following:
>
> warning: format ‘%lx’ expects argument of type ‘long unsigned int’,
> but argument 4 has type ‘unsigned int’ [-Wformat]
>
> This issue does not affect the object code, but it should be
> fixed. Setting the format specifier to %02x and adding a cast of (int)
> before the "size_of" will fix it on both sets of systems.

Ewww, I didn't realize PowerPC 32 was this ugly :( Adding (long) as a
cast would have the same effect here, but we will end up with an ugly
cast in either case.

>> +static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
>> +{
>> +	u32 val32;
>> +	u32 rf_amode, rf_bmode = 0, lstf;
>> +
>> +	/* Check continuous TX and Packet TX */
>> +	lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
>> +
>> +	if (lstf & OFDM_LSTF_MASK) {
>> +		/* Disable all continuous TX */
>> +		val32 = lstf & ~OFDM_LSTF_MASK;
>> +		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
>> +
>> +		/* Read original RF mode Path A */
>> +		rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC);
>
> The compiler on the PPC system (V4.6.3) is not as good at determining
> if a variable has been set as is V4.8.3. It generates the warning
> "warning: ‘rf_amode’ may be used uninitialized in this function
> [-Wuninitialized]" for the above statement. As I hate to initialize
> any variable that does not need it, this one should probably be left
> alone; however, you may wish to add a comment.

A comment would suffice, but the question is really whether it adds
value to the code doing so - since 99.99% of users will never see this
compiler warning. I am not opposed to zero initializing it, as I had to
do the same with rf_bmode.

>> +static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>> +			struct ieee80211_tx_control *control,
>> +			struct sk_buff *skb)
>> +{
>> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
>> +	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
>> +	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
>> +	struct rtl8xxxu_priv *priv = hw->priv;
>> +	struct rtl8xxxu_tx_desc *tx_desc;
>> +	struct ieee80211_sta *sta = NULL;
>> +	struct rtl8xxxu_sta_priv *sta_priv = NULL;
>> +	struct device *dev = &priv->udev->dev;
>> +	struct urb *urb;
>> +	u32 queue, rate;
>> +	u16 pktlen = skb->len;
>> +	u16 seq_number;
>> +	u16 rate_flag = tx_info->control.rates[0].flags;
>> +	int ret;
>> +
>> +	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
>> +		dev_warn(dev,
>> +			 "%s: Not enough headroom (%i) for tx descriptor\n",
>> +			 __func__, skb_headroom(skb));
>> +		goto error;
>> +	}
>> +
>> +	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
>> +		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
>> +			 __func__, skb->len);
>> +		goto error;
>> +	}
>> +
>> +	urb = usb_alloc_urb(0, GFP_KERNEL);
>
> The above statement generated a "scheduling while atomic" splat. The
> gfp_t argument needs to be GFP_KERNEL.

You are seeing scheduling while atomic in the TX path? That just seems
wrong to me - Johannes is the mac80211 TX path not meant to allow
sleeping?

I have never seen this on x86 and I have been running the driver for a
long time. It is puzzling this causes a problem on PowerPC. It there
something special in the config for it? I am inclined to say there is
something wrong with the PPC32 setup rather than with my usage of
GFP_KERNEL in the TX path.

>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
> 0xff, 0xff),
>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>
> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.

Were you happy with the results, or did it cause problems? Ie. did you
try on x86 or on PPC32?

> Some comments that are not part of the review, but may be of interest
> to potential users:
>
> 1. The gain settings on the RTL81{88,92}CU parts greatly reduce its
> usefullnes. My Edimax 7811 can only find 1 of my 5 local APs in a
> scan. It can connect to that AP, but achieves less than 10 Mbps for
> both RX and TX operations. I expect to be able to discover better
> initialization variables, but that may take a while.

Interesting, I am trying to use the settings coming out of the efuse,
but it is not impossible I do something wrong with them. So far I got
decent results with 8192cu devices, But my testing with those has been
limited.

> 2. The driver fails to produce a wireless device on the PowerPC
> because the firmware ready to run bit is never set. I have not seen
> any reason for this to be a big-endian issue, and it may be another
> pecularity of the USB subsystem on that laptop. For example, USB
> devices that are plugged in at boot time fail, even though they work
> if hot plugged into a running system.
>
> For a new driver written from scratch, it looks pretty good.

Thanks for the comments, much appreciated!

I don't think any of this is showstopper material for inclusion right
now, albeit I do want to address them.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 18:41     ` Jes Sorensen
@ 2015-08-30 21:02       ` Jes Sorensen
  2015-08-30 23:51       ` Larry Finger
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-08-30 21:02 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, kvalo, johannes

Jes Sorensen <Jes.Sorensen@redhat.com> writes:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>> +static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>>> +			struct ieee80211_tx_control *control,
>>> +			struct sk_buff *skb)
>>> +{
>>> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
>>> +	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
>>> +	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
>>> +	struct rtl8xxxu_priv *priv = hw->priv;
>>> +	struct rtl8xxxu_tx_desc *tx_desc;
>>> +	struct ieee80211_sta *sta = NULL;
>>> +	struct rtl8xxxu_sta_priv *sta_priv = NULL;
>>> +	struct device *dev = &priv->udev->dev;
>>> +	struct urb *urb;
>>> +	u32 queue, rate;
>>> +	u16 pktlen = skb->len;
>>> +	u16 seq_number;
>>> +	u16 rate_flag = tx_info->control.rates[0].flags;
>>> +	int ret;
>>> +
>>> +	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
>>> +		dev_warn(dev,
>>> +			 "%s: Not enough headroom (%i) for tx descriptor\n",
>>> +			 __func__, skb_headroom(skb));
>>> +		goto error;
>>> +	}
>>> +
>>> +	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
>>> +		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
>>> +			 __func__, skb->len);
>>> +		goto error;
>>> +	}
>>> +
>>> +	urb = usb_alloc_urb(0, GFP_KERNEL);
>>
>> The above statement generated a "scheduling while atomic" splat. The
>> gfp_t argument needs to be GFP_KERNEL.
>
> You are seeing scheduling while atomic in the TX path? That just seems
> wrong to me - Johannes is the mac80211 TX path not meant to allow
> sleeping?

I went and checked include/net/mac80211.h and indeed you are right.
Updated patch fixing these issues, and hopefully mutex issue, coming you
way in a minute.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
@ 2015-08-30 21:02 Jes.Sorensen
  2015-08-30 21:02 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
  2015-09-06 14:43 ` [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Kalle Valo
  0 siblings, 2 replies; 68+ messages in thread
From: Jes.Sorensen @ 2015-08-30 21:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: jes.sorensen, kvalo, Larry.Finger

From: Jes Sorensen <Jes.Sorensen@redhat.com>

Hi,

I finally found some time to work on rtl8xxxu again. Since the
previously version posted some months ago, I fixed up a number of
bugs. I also added support for a range of other Realtek based USB
devices. The driver now supports rtl8723au, rtl8188cu, rtl8188ru, and
rtl8192cu. It should work on rtl8191cu devices as well.

Per default only devices I have actually tested will be enabled. If
you are interested in trying it out with other 8188cu/8188ru/819[12]cu
dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
test results back to me.

Note if you enable this driver, it may clash with CONFIG_RTL8192U,
CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
to which module you load and/or use modprobe blacklists.

This driver is still work in progress. I have used it as my primary
driver for the last six months, and I find it to be very stable. It
seems suitable for mainline inclusion at this point.

v2 of this patch contains fixes for issues reported by Larry Finger.
I checked include/net/mac80211.h and the .tx function does indeed have
to be atomic. In addition I found a race condition in
rtl8723a_h2c_cmd() which may explain the mutex issue Larry saw.

Cheers,
Jes


Jes Sorensen (1):
  New driver: rtl8xxxu (mac80211)

 MAINTAINERS                          |    7 +
 drivers/net/wireless/Kconfig         |   32 +
 drivers/net/wireless/Makefile        |    2 +
 drivers/net/wireless/rtl8xxxu.c      | 5829 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/rtl8xxxu.h      |  597 ++++
 drivers/net/wireless/rtl8xxxu_regs.h |  980 ++++++
 6 files changed, 7447 insertions(+)
 create mode 100644 drivers/net/wireless/rtl8xxxu.c
 create mode 100644 drivers/net/wireless/rtl8xxxu.h
 create mode 100644 drivers/net/wireless/rtl8xxxu_regs.h

-- 
2.1.0


^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 21:02 [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
@ 2015-08-30 21:02 ` Jes.Sorensen
  2015-09-06 14:59   ` Kalle Valo
  2015-09-06 14:43 ` [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Kalle Valo
  1 sibling, 1 reply; 68+ messages in thread
From: Jes.Sorensen @ 2015-08-30 21:02 UTC (permalink / raw)
  To: linux-wireless; +Cc: jes.sorensen, kvalo, Larry.Finger

From: Jes Sorensen <Jes.Sorensen@redhat.com>

This is an alternate driver for a number of Realtek WiFi USB devices,
including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
It was written from scratch utilizing the Linux mac80211 stack.

After spending months cleaning up the vendor provided rtl8723au
driver, which comes with it's own 802.11 stack included, I decided to
rewrite this driver from the bottom up.

Many thanks to Johannes Berg for 802.11 insights and help and Larry
Finger for help with the vendor driver.

The full git log for the development of this driver can be found here:
git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
    branch rtl8723au-mac80211

This driver is still under development, but has proven to be very
stable for me. It currently supports station mode only. It has support
for OFDM and CCK rates, as well as AMPDU. It does lack certain
features found in the staging driver, such as power management and
40MHz channel support. In addition it does not support AD-HOC, AP, and
monitor mode support at this point.

The driver is known to work with the following devices:
Lenovo Yoga (rtl8723au)
TP-Link TL-WN823N (rtl8192cu)
Etekcity 6R (rtl8188cu)
Daffodil LAN03 (rtl8188cu)
Alfa AWUS036NHR (rtl8188ru)

Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>

v2: Contains fixes for problems reported by Larry Finger
---
 MAINTAINERS                          |    7 +
 drivers/net/wireless/Kconfig         |   32 +
 drivers/net/wireless/Makefile        |    2 +
 drivers/net/wireless/rtl8xxxu.c      | 5829 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/rtl8xxxu.h      |  597 ++++
 drivers/net/wireless/rtl8xxxu_regs.h |  980 ++++++
 6 files changed, 7447 insertions(+)
 create mode 100644 drivers/net/wireless/rtl8xxxu.c
 create mode 100644 drivers/net/wireless/rtl8xxxu.h
 create mode 100644 drivers/net/wireless/rtl8xxxu_regs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b60e2b2..54b03bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8699,6 +8699,13 @@ S:	Maintained
 F:	drivers/net/wireless/rtlwifi/
 F:	drivers/net/wireless/rtlwifi/rtl8192ce/
 
+RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
+M:	Jes Sorensen <Jes.Sorensen@redhat.com>
+L:	linux-wireless@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
+S:	Maintained
+F:	drivers/net/wireless/rtl8xxxu*.[ch]
+
 S3 SAVAGE FRAMEBUFFER DRIVER
 M:	Antonino Daplas <adaplas@gmail.com>
 L:	linux-fbdev@vger.kernel.org
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index a63ab2e..def6cfd 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -243,6 +243,38 @@ config ADM8211
 
 	  Thanks to Infineon-ADMtek for their support of this driver.
 
+config RTL8XXXU
+	tristate "RTL8723AU/RTL8188[CR]U/RTL819[12]CU (mac80211) support"
+	depends on MAC80211 && USB
+	---help---
+	  This is an alternative driver for various Realtek RTL8XXX
+	  parts written to utilize the Linux mac80211 stack.
+	  The driver is known to work with a number of RTL8723AU,
+	  RL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU devices
+
+	  This driver is under development and has a limited feature
+	  set. In particular it does not yet support 40MHz channels
+	  and power management. However it should have a smaller
+	  memory footprint than the vendor drivers and benetifs
+	  from the in kernel mac80211 stack.
+
+	  It can coexist with drivers from drivers/staging/rtl8723au,
+	  drivers/staging/rtl8192u, and drivers/net/wireless/rtlwifi,
+	  but you will need to control which module you wish to load.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called r8xxxu.  If unsure, say N.
+
+config RTL8XXXU_UNTESTED
+	bool "Include support for untested Realtek 8xxx USB devices"
+	depends on RTL8XXXU
+	---help---
+	  This option enables detection of Realtek 8723/8188/8191/8192 WiFi
+	  USB devices which have not been tested directly by the driver
+	  author or reported to be working by third parties.
+
+	  Please report your results!
+
 config MAC80211_HWSIM
 	tristate "Simulated radio testing tool for mac80211"
 	depends on MAC80211
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 6b9e729..593bdef 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -39,6 +39,8 @@ obj-$(CONFIG_LIBERTAS_THINFIRM)	+= libertas_tf/
 
 obj-$(CONFIG_ADM8211)	+= adm8211.o
 
+obj-$(CONFIG_RTL8XXXU)	+= rtl8xxxu.o
+
 obj-$(CONFIG_MWL8K)	+= mwl8k.o
 
 obj-$(CONFIG_IWLWIFI)	+= iwlwifi/
diff --git a/drivers/net/wireless/rtl8xxxu.c b/drivers/net/wireless/rtl8xxxu.c
new file mode 100644
index 0000000..a1390b0
--- /dev/null
+++ b/drivers/net/wireless/rtl8xxxu.c
@@ -0,0 +1,5829 @@
+/*
+ * RTL8XXXU mac80211 USB driver
+ *
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Portions, notably calibration code:
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This driver was written as a replacement for the vendor provided
+ * rtl8723au driver. As the Realtek 8xxx chips are very similar in
+ * their programming interface, I have started adding support for
+ * additional 8xxx chips like the 8192cu, 8188cus, etc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/moduleparam.h>
+#include <net/mac80211.h>
+#include "rtl8xxxu.h"
+#include "rtl8xxxu_regs.h"
+
+#define DRIVER_NAME "rtl8xxxu"
+
+static int rtl8xxxu_debug /* = 0 */; /* Avoid pointless checkpatch noise */
+
+MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>");
+MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin");
+
+module_param_named(debug, rtl8xxxu_debug, int, 0600);
+MODULE_PARM_DESC(debug, "Set debug mask");
+
+#define USB_VENDOR_ID_REALTEK		0x0bda
+/* Minimum IEEE80211_MAX_FRAME_LEN */
+#define RTL_RX_BUFFER_SIZE		IEEE80211_MAX_FRAME_LEN
+
+static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb);
+
+static struct ieee80211_rate rtl8xxxu_rates[] = {
+	{ .bitrate = 10, .hw_value = DESC_RATE_1M, .flags = 0 },
+	{ .bitrate = 20, .hw_value = DESC_RATE_2M, .flags = 0 },
+	{ .bitrate = 55, .hw_value = DESC_RATE_5_5M, .flags = 0 },
+	{ .bitrate = 110, .hw_value = DESC_RATE_11M, .flags = 0 },
+	{ .bitrate = 60, .hw_value = DESC_RATE_6M, .flags = 0 },
+	{ .bitrate = 90, .hw_value = DESC_RATE_9M, .flags = 0 },
+	{ .bitrate = 120, .hw_value = DESC_RATE_12M, .flags = 0 },
+	{ .bitrate = 180, .hw_value = DESC_RATE_18M, .flags = 0 },
+	{ .bitrate = 240, .hw_value = DESC_RATE_24M, .flags = 0 },
+	{ .bitrate = 360, .hw_value = DESC_RATE_36M, .flags = 0 },
+	{ .bitrate = 480, .hw_value = DESC_RATE_48M, .flags = 0 },
+	{ .bitrate = 540, .hw_value = DESC_RATE_54M, .flags = 0 },
+};
+
+static struct ieee80211_channel rtl8xxxu_channels_2g[] = {
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2412,
+	  .hw_value = 1, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2417,
+	  .hw_value = 2, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2422,
+	  .hw_value = 3, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2427,
+	  .hw_value = 4, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2432,
+	  .hw_value = 5, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2437,
+	  .hw_value = 6, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2442,
+	  .hw_value = 7, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2447,
+	  .hw_value = 8, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2452,
+	  .hw_value = 9, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2457,
+	  .hw_value = 10, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2462,
+	  .hw_value = 11, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2467,
+	  .hw_value = 12, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2472,
+	  .hw_value = 13, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2484,
+	  .hw_value = 14, .max_power = 30 }
+};
+
+static struct ieee80211_supported_band rtl8xxxu_supported_band = {
+	.channels = rtl8xxxu_channels_2g,
+	.n_channels = ARRAY_SIZE(rtl8xxxu_channels_2g),
+	.bitrates = rtl8xxxu_rates,
+	.n_bitrates = ARRAY_SIZE(rtl8xxxu_rates),
+};
+
+static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = {
+	{0x420, 0x80}, {0x423, 0x00}, {0x430, 0x00}, {0x431, 0x00},
+	{0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05},
+	{0x436, 0x06}, {0x437, 0x07}, {0x438, 0x00}, {0x439, 0x00},
+	{0x43a, 0x00}, {0x43b, 0x01}, {0x43c, 0x04}, {0x43d, 0x05},
+	{0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01},
+	{0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f},
+	{0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72},
+	{0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x462, 0x08},
+	{0x463, 0x03}, {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff},
+	{0x4cd, 0xff}, {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2},
+	{0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3},
+	{0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4},
+	{0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4},
+	{0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a},
+	{0x515, 0x10}, {0x516, 0x0a}, {0x517, 0x10}, {0x51a, 0x16},
+	{0x524, 0x0f}, {0x525, 0x4f}, {0x546, 0x40}, {0x547, 0x00},
+	{0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, {0x55a, 0x02},
+	{0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a},
+	{0x652, 0x20}, {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e},
+	{0x63f, 0x0e}, {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43},
+	{0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43},
+	{0x70a, 0x65}, {0x70b, 0x87}, {0xffff, 0xff},
+};
+
+static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = {
+	{0x800, 0x80040000}, {0x804, 0x00000003},
+	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+	{0x810, 0x10001331}, {0x814, 0x020c3d10},
+	{0x818, 0x02200385}, {0x81c, 0x00000000},
+	{0x820, 0x01000100}, {0x824, 0x00390004},
+	{0x828, 0x00000000}, {0x82c, 0x00000000},
+	{0x830, 0x00000000}, {0x834, 0x00000000},
+	{0x838, 0x00000000}, {0x83c, 0x00000000},
+	{0x840, 0x00010000}, {0x844, 0x00000000},
+	{0x848, 0x00000000}, {0x84c, 0x00000000},
+	{0x850, 0x00000000}, {0x854, 0x00000000},
+	{0x858, 0x569a569a}, {0x85c, 0x001b25a4},
+	{0x860, 0x66f60110}, {0x864, 0x061f0130},
+	{0x868, 0x00000000}, {0x86c, 0x32323200},
+	{0x870, 0x07000760}, {0x874, 0x22004000},
+	{0x878, 0x00000808}, {0x87c, 0x00000000},
+	{0x880, 0xc0083070}, {0x884, 0x000004d5},
+	{0x888, 0x00000000}, {0x88c, 0xccc000c0},
+	{0x890, 0x00000800}, {0x894, 0xfffffffe},
+	{0x898, 0x40302010}, {0x89c, 0x00706050},
+	{0x900, 0x00000000}, {0x904, 0x00000023},
+	{0x908, 0x00000000}, {0x90c, 0x81121111},
+	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
+	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
+	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
+	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
+	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
+	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
+	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
+	{0xa78, 0x00000900},
+	{0xc00, 0x48071d40}, {0xc04, 0x03a05611},
+	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
+	{0xc10, 0x08800000}, {0xc14, 0x40000100},
+	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
+	{0xc20, 0x00000000}, {0xc24, 0x00000000},
+	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
+	{0xc30, 0x69e9ac44}, {0xc34, 0x469652af},
+	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
+	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
+	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
+	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
+	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
+	{0xc60, 0x00000000}, {0xc64, 0x7112848b},
+	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
+	{0xc70, 0x2c7f000d}, {0xc74, 0x018610db},
+	{0xc78, 0x0000001f}, {0xc7c, 0x00b91612},
+	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
+	{0xc88, 0x40000100}, {0xc8c, 0x20200000},
+	{0xc90, 0x00121820}, {0xc94, 0x00000000},
+	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
+	{0xca0, 0x00000000}, {0xca4, 0x00000080},
+	{0xca8, 0x00000000}, {0xcac, 0x00000000},
+	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
+	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
+	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
+	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
+	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
+	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
+	{0xce0, 0x00222222}, {0xce4, 0x00000000},
+	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
+	{0xd00, 0x00080740}, {0xd04, 0x00020401},
+	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
+	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
+	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
+	{0xd30, 0x00000000}, {0xd34, 0x80608000},
+	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
+	{0xd40, 0x00000000}, {0xd44, 0x00000000},
+	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
+	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
+	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
+	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
+	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
+	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
+	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
+	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
+	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
+	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
+	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
+	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
+	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
+	{0xe5c, 0x28160d05}, {0xe60, 0x00000008},
+	{0xe68, 0x001b25a4}, {0xe6c, 0x631b25a0},
+	{0xe70, 0x631b25a0}, {0xe74, 0x081b25a0},
+	{0xe78, 0x081b25a0}, {0xe7c, 0x081b25a0},
+	{0xe80, 0x081b25a0}, {0xe84, 0x631b25a0},
+	{0xe88, 0x081b25a0}, {0xe8c, 0x631b25a0},
+	{0xed0, 0x631b25a0}, {0xed4, 0x631b25a0},
+	{0xed8, 0x631b25a0}, {0xedc, 0x001b25a0},
+	{0xee0, 0x001b25a0}, {0xeec, 0x6b1b25a0},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8192cu_phy_2t_init_table[] = {
+	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
+	{0x800, 0x80040002}, {0x804, 0x00000003},
+	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+	{0x810, 0x10000330}, {0x814, 0x020c3d10},
+	{0x818, 0x02200385}, {0x81c, 0x00000000},
+	{0x820, 0x01000100}, {0x824, 0x00390004},
+	{0x828, 0x01000100}, {0x82c, 0x00390004},
+	{0x830, 0x27272727}, {0x834, 0x27272727},
+	{0x838, 0x27272727}, {0x83c, 0x27272727},
+	{0x840, 0x00010000}, {0x844, 0x00010000},
+	{0x848, 0x27272727}, {0x84c, 0x27272727},
+	{0x850, 0x00000000}, {0x854, 0x00000000},
+	{0x858, 0x569a569a}, {0x85c, 0x0c1b25a4},
+	{0x860, 0x66e60230}, {0x864, 0x061f0130},
+	{0x868, 0x27272727}, {0x86c, 0x2b2b2b27},
+	{0x870, 0x07000700}, {0x874, 0x22184000},
+	{0x878, 0x08080808}, {0x87c, 0x00000000},
+	{0x880, 0xc0083070}, {0x884, 0x000004d5},
+	{0x888, 0x00000000}, {0x88c, 0xcc0000c0},
+	{0x890, 0x00000800}, {0x894, 0xfffffffe},
+	{0x898, 0x40302010}, {0x89c, 0x00706050},
+	{0x900, 0x00000000}, {0x904, 0x00000023},
+	{0x908, 0x00000000}, {0x90c, 0x81121313},
+	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
+	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
+	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
+	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
+	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
+	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
+	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
+	{0xc00, 0x48071d40}, {0xc04, 0x03a05633},
+	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
+	{0xc10, 0x08800000}, {0xc14, 0x40000100},
+	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
+	{0xc20, 0x00000000}, {0xc24, 0x00000000},
+	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
+	{0xc30, 0x69e9ac44}, {0xc34, 0x469652cf},
+	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
+	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
+	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
+	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
+	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
+	{0xc60, 0x00000000}, {0xc64, 0x5116848b},
+	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
+	{0xc70, 0x2c7f000d}, {0xc74, 0x2186115b},
+	{0xc78, 0x0000001f}, {0xc7c, 0x00b99612},
+	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
+	{0xc88, 0x40000100}, {0xc8c, 0xa0e40000},
+	{0xc90, 0x00121820}, {0xc94, 0x00000000},
+	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
+	{0xca0, 0x00000000}, {0xca4, 0x00000080},
+	{0xca8, 0x00000000}, {0xcac, 0x00000000},
+	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
+	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
+	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
+	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
+	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
+	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
+	{0xce0, 0x00222222}, {0xce4, 0x00000000},
+	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
+	{0xd00, 0x00080740}, {0xd04, 0x00020403},
+	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
+	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
+	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
+	{0xd30, 0x00000000}, {0xd34, 0x80608000},
+	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
+	{0xd40, 0x00000000}, {0xd44, 0x00000000},
+	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
+	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
+	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
+	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
+	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
+	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
+	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
+	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
+	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
+	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
+	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
+	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
+	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
+	{0xe5c, 0x28160d05}, {0xe60, 0x00000010},
+	{0xe68, 0x001b25a4}, {0xe6c, 0x63db25a4},
+	{0xe70, 0x63db25a4}, {0xe74, 0x0c1b25a4},
+	{0xe78, 0x0c1b25a4}, {0xe7c, 0x0c1b25a4},
+	{0xe80, 0x0c1b25a4}, {0xe84, 0x63db25a4},
+	{0xe88, 0x0c1b25a4}, {0xe8c, 0x63db25a4},
+	{0xed0, 0x63db25a4}, {0xed4, 0x63db25a4},
+	{0xed8, 0x63db25a4}, {0xedc, 0x001b25a4},
+	{0xee0, 0x001b25a4}, {0xeec, 0x6fdb25a4},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8188ru_phy_1t_highpa_table[] = {
+	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
+	{0x040, 0x000c0004}, {0x800, 0x80040000},
+	{0x804, 0x00000001}, {0x808, 0x0000fc00},
+	{0x80c, 0x0000000a}, {0x810, 0x10005388},
+	{0x814, 0x020c3d10}, {0x818, 0x02200385},
+	{0x81c, 0x00000000}, {0x820, 0x01000100},
+	{0x824, 0x00390204}, {0x828, 0x00000000},
+	{0x82c, 0x00000000}, {0x830, 0x00000000},
+	{0x834, 0x00000000}, {0x838, 0x00000000},
+	{0x83c, 0x00000000}, {0x840, 0x00010000},
+	{0x844, 0x00000000}, {0x848, 0x00000000},
+	{0x84c, 0x00000000}, {0x850, 0x00000000},
+	{0x854, 0x00000000}, {0x858, 0x569a569a},
+	{0x85c, 0x001b25a4}, {0x860, 0x66e60230},
+	{0x864, 0x061f0130}, {0x868, 0x00000000},
+	{0x86c, 0x20202000}, {0x870, 0x03000300},
+	{0x874, 0x22004000}, {0x878, 0x00000808},
+	{0x87c, 0x00ffc3f1}, {0x880, 0xc0083070},
+	{0x884, 0x000004d5}, {0x888, 0x00000000},
+	{0x88c, 0xccc000c0}, {0x890, 0x00000800},
+	{0x894, 0xfffffffe}, {0x898, 0x40302010},
+	{0x89c, 0x00706050}, {0x900, 0x00000000},
+	{0x904, 0x00000023}, {0x908, 0x00000000},
+	{0x90c, 0x81121111}, {0xa00, 0x00d047c8},
+	{0xa04, 0x80ff000c}, {0xa08, 0x8c838300},
+	{0xa0c, 0x2e68120f}, {0xa10, 0x9500bb78},
+	{0xa14, 0x11144028}, {0xa18, 0x00881117},
+	{0xa1c, 0x89140f00}, {0xa20, 0x15160000},
+	{0xa24, 0x070b0f12}, {0xa28, 0x00000104},
+	{0xa2c, 0x00d30000}, {0xa70, 0x101fbf00},
+	{0xa74, 0x00000007}, {0xc00, 0x48071d40},
+	{0xc04, 0x03a05611}, {0xc08, 0x000000e4},
+	{0xc0c, 0x6c6c6c6c}, {0xc10, 0x08800000},
+	{0xc14, 0x40000100}, {0xc18, 0x08800000},
+	{0xc1c, 0x40000100}, {0xc20, 0x00000000},
+	{0xc24, 0x00000000}, {0xc28, 0x00000000},
+	{0xc2c, 0x00000000}, {0xc30, 0x69e9ac44},
+	{0xc34, 0x469652cf}, {0xc38, 0x49795994},
+	{0xc3c, 0x0a97971c}, {0xc40, 0x1f7c403f},
+	{0xc44, 0x000100b7}, {0xc48, 0xec020107},
+	{0xc4c, 0x007f037f}, {0xc50, 0x6954342e},
+	{0xc54, 0x43bc0094}, {0xc58, 0x6954342f},
+	{0xc5c, 0x433c0094}, {0xc60, 0x00000000},
+	{0xc64, 0x5116848b}, {0xc68, 0x47c00bff},
+	{0xc6c, 0x00000036}, {0xc70, 0x2c46000d},
+	{0xc74, 0x018610db}, {0xc78, 0x0000001f},
+	{0xc7c, 0x00b91612}, {0xc80, 0x24000090},
+	{0xc84, 0x20f60000}, {0xc88, 0x24000090},
+	{0xc8c, 0x20200000}, {0xc90, 0x00121820},
+	{0xc94, 0x00000000}, {0xc98, 0x00121820},
+	{0xc9c, 0x00007f7f}, {0xca0, 0x00000000},
+	{0xca4, 0x00000080}, {0xca8, 0x00000000},
+	{0xcac, 0x00000000}, {0xcb0, 0x00000000},
+	{0xcb4, 0x00000000}, {0xcb8, 0x00000000},
+	{0xcbc, 0x28000000}, {0xcc0, 0x00000000},
+	{0xcc4, 0x00000000}, {0xcc8, 0x00000000},
+	{0xccc, 0x00000000}, {0xcd0, 0x00000000},
+	{0xcd4, 0x00000000}, {0xcd8, 0x64b22427},
+	{0xcdc, 0x00766932}, {0xce0, 0x00222222},
+	{0xce4, 0x00000000}, {0xce8, 0x37644302},
+	{0xcec, 0x2f97d40c}, {0xd00, 0x00080740},
+	{0xd04, 0x00020401}, {0xd08, 0x0000907f},
+	{0xd0c, 0x20010201}, {0xd10, 0xa0633333},
+	{0xd14, 0x3333bc43}, {0xd18, 0x7a8f5b6b},
+	{0xd2c, 0xcc979975}, {0xd30, 0x00000000},
+	{0xd34, 0x80608000}, {0xd38, 0x00000000},
+	{0xd3c, 0x00027293}, {0xd40, 0x00000000},
+	{0xd44, 0x00000000}, {0xd48, 0x00000000},
+	{0xd4c, 0x00000000}, {0xd50, 0x6437140a},
+	{0xd54, 0x00000000}, {0xd58, 0x00000000},
+	{0xd5c, 0x30032064}, {0xd60, 0x4653de68},
+	{0xd64, 0x04518a3c}, {0xd68, 0x00002101},
+	{0xd6c, 0x2a201c16}, {0xd70, 0x1812362e},
+	{0xd74, 0x322c2220}, {0xd78, 0x000e3c24},
+	{0xe00, 0x24242424}, {0xe04, 0x24242424},
+	{0xe08, 0x03902024}, {0xe10, 0x24242424},
+	{0xe14, 0x24242424}, {0xe18, 0x24242424},
+	{0xe1c, 0x24242424}, {0xe28, 0x00000000},
+	{0xe30, 0x1000dc1f}, {0xe34, 0x10008c1f},
+	{0xe38, 0x02140102}, {0xe3c, 0x681604c2},
+	{0xe40, 0x01007c00}, {0xe44, 0x01004800},
+	{0xe48, 0xfb000000}, {0xe4c, 0x000028d1},
+	{0xe50, 0x1000dc1f}, {0xe54, 0x10008c1f},
+	{0xe58, 0x02140102}, {0xe5c, 0x28160d05},
+	{0xe60, 0x00000008}, {0xe68, 0x001b25a4},
+	{0xe6c, 0x631b25a0}, {0xe70, 0x631b25a0},
+	{0xe74, 0x081b25a0}, {0xe78, 0x081b25a0},
+	{0xe7c, 0x081b25a0}, {0xe80, 0x081b25a0},
+	{0xe84, 0x631b25a0}, {0xe88, 0x081b25a0},
+	{0xe8c, 0x631b25a0}, {0xed0, 0x631b25a0},
+	{0xed4, 0x631b25a0}, {0xed8, 0x631b25a0},
+	{0xedc, 0x001b25a0}, {0xee0, 0x001b25a0},
+	{0xeec, 0x6b1b25a0}, {0xee8, 0x31555448},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_standard_table[] = {
+	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
+	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
+	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
+	{0xc78, 0x7a060001}, {0xc78, 0x79070001},
+	{0xc78, 0x78080001}, {0xc78, 0x77090001},
+	{0xc78, 0x760a0001}, {0xc78, 0x750b0001},
+	{0xc78, 0x740c0001}, {0xc78, 0x730d0001},
+	{0xc78, 0x720e0001}, {0xc78, 0x710f0001},
+	{0xc78, 0x70100001}, {0xc78, 0x6f110001},
+	{0xc78, 0x6e120001}, {0xc78, 0x6d130001},
+	{0xc78, 0x6c140001}, {0xc78, 0x6b150001},
+	{0xc78, 0x6a160001}, {0xc78, 0x69170001},
+	{0xc78, 0x68180001}, {0xc78, 0x67190001},
+	{0xc78, 0x661a0001}, {0xc78, 0x651b0001},
+	{0xc78, 0x641c0001}, {0xc78, 0x631d0001},
+	{0xc78, 0x621e0001}, {0xc78, 0x611f0001},
+	{0xc78, 0x60200001}, {0xc78, 0x49210001},
+	{0xc78, 0x48220001}, {0xc78, 0x47230001},
+	{0xc78, 0x46240001}, {0xc78, 0x45250001},
+	{0xc78, 0x44260001}, {0xc78, 0x43270001},
+	{0xc78, 0x42280001}, {0xc78, 0x41290001},
+	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
+	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
+	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
+	{0xc78, 0x21300001}, {0xc78, 0x20310001},
+	{0xc78, 0x06320001}, {0xc78, 0x05330001},
+	{0xc78, 0x04340001}, {0xc78, 0x03350001},
+	{0xc78, 0x02360001}, {0xc78, 0x01370001},
+	{0xc78, 0x00380001}, {0xc78, 0x00390001},
+	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
+	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
+	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
+	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
+	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
+	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
+	{0xc78, 0x7a460001}, {0xc78, 0x79470001},
+	{0xc78, 0x78480001}, {0xc78, 0x77490001},
+	{0xc78, 0x764a0001}, {0xc78, 0x754b0001},
+	{0xc78, 0x744c0001}, {0xc78, 0x734d0001},
+	{0xc78, 0x724e0001}, {0xc78, 0x714f0001},
+	{0xc78, 0x70500001}, {0xc78, 0x6f510001},
+	{0xc78, 0x6e520001}, {0xc78, 0x6d530001},
+	{0xc78, 0x6c540001}, {0xc78, 0x6b550001},
+	{0xc78, 0x6a560001}, {0xc78, 0x69570001},
+	{0xc78, 0x68580001}, {0xc78, 0x67590001},
+	{0xc78, 0x665a0001}, {0xc78, 0x655b0001},
+	{0xc78, 0x645c0001}, {0xc78, 0x635d0001},
+	{0xc78, 0x625e0001}, {0xc78, 0x615f0001},
+	{0xc78, 0x60600001}, {0xc78, 0x49610001},
+	{0xc78, 0x48620001}, {0xc78, 0x47630001},
+	{0xc78, 0x46640001}, {0xc78, 0x45650001},
+	{0xc78, 0x44660001}, {0xc78, 0x43670001},
+	{0xc78, 0x42680001}, {0xc78, 0x41690001},
+	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
+	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
+	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
+	{0xc78, 0x21700001}, {0xc78, 0x20710001},
+	{0xc78, 0x06720001}, {0xc78, 0x05730001},
+	{0xc78, 0x04740001}, {0xc78, 0x03750001},
+	{0xc78, 0x02760001}, {0xc78, 0x01770001},
+	{0xc78, 0x00780001}, {0xc78, 0x00790001},
+	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
+	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
+	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
+	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
+	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
+	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
+	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
+	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
+	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
+	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
+	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
+	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
+	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
+	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
+	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
+	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
+	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
+	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
+	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
+	{0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_highpa_table[] = {
+	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
+	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
+	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
+	{0xc78, 0x7b060001}, {0xc78, 0x7b070001},
+	{0xc78, 0x7b080001}, {0xc78, 0x7a090001},
+	{0xc78, 0x790a0001}, {0xc78, 0x780b0001},
+	{0xc78, 0x770c0001}, {0xc78, 0x760d0001},
+	{0xc78, 0x750e0001}, {0xc78, 0x740f0001},
+	{0xc78, 0x73100001}, {0xc78, 0x72110001},
+	{0xc78, 0x71120001}, {0xc78, 0x70130001},
+	{0xc78, 0x6f140001}, {0xc78, 0x6e150001},
+	{0xc78, 0x6d160001}, {0xc78, 0x6c170001},
+	{0xc78, 0x6b180001}, {0xc78, 0x6a190001},
+	{0xc78, 0x691a0001}, {0xc78, 0x681b0001},
+	{0xc78, 0x671c0001}, {0xc78, 0x661d0001},
+	{0xc78, 0x651e0001}, {0xc78, 0x641f0001},
+	{0xc78, 0x63200001}, {0xc78, 0x62210001},
+	{0xc78, 0x61220001}, {0xc78, 0x60230001},
+	{0xc78, 0x46240001}, {0xc78, 0x45250001},
+	{0xc78, 0x44260001}, {0xc78, 0x43270001},
+	{0xc78, 0x42280001}, {0xc78, 0x41290001},
+	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
+	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
+	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
+	{0xc78, 0x21300001}, {0xc78, 0x20310001},
+	{0xc78, 0x06320001}, {0xc78, 0x05330001},
+	{0xc78, 0x04340001}, {0xc78, 0x03350001},
+	{0xc78, 0x02360001}, {0xc78, 0x01370001},
+	{0xc78, 0x00380001}, {0xc78, 0x00390001},
+	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
+	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
+	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
+	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
+	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
+	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
+	{0xc78, 0x7b460001}, {0xc78, 0x7b470001},
+	{0xc78, 0x7b480001}, {0xc78, 0x7a490001},
+	{0xc78, 0x794a0001}, {0xc78, 0x784b0001},
+	{0xc78, 0x774c0001}, {0xc78, 0x764d0001},
+	{0xc78, 0x754e0001}, {0xc78, 0x744f0001},
+	{0xc78, 0x73500001}, {0xc78, 0x72510001},
+	{0xc78, 0x71520001}, {0xc78, 0x70530001},
+	{0xc78, 0x6f540001}, {0xc78, 0x6e550001},
+	{0xc78, 0x6d560001}, {0xc78, 0x6c570001},
+	{0xc78, 0x6b580001}, {0xc78, 0x6a590001},
+	{0xc78, 0x695a0001}, {0xc78, 0x685b0001},
+	{0xc78, 0x675c0001}, {0xc78, 0x665d0001},
+	{0xc78, 0x655e0001}, {0xc78, 0x645f0001},
+	{0xc78, 0x63600001}, {0xc78, 0x62610001},
+	{0xc78, 0x61620001}, {0xc78, 0x60630001},
+	{0xc78, 0x46640001}, {0xc78, 0x45650001},
+	{0xc78, 0x44660001}, {0xc78, 0x43670001},
+	{0xc78, 0x42680001}, {0xc78, 0x41690001},
+	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
+	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
+	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
+	{0xc78, 0x21700001}, {0xc78, 0x20710001},
+	{0xc78, 0x06720001}, {0xc78, 0x05730001},
+	{0xc78, 0x04740001}, {0xc78, 0x03750001},
+	{0xc78, 0x02760001}, {0xc78, 0x01770001},
+	{0xc78, 0x00780001}, {0xc78, 0x00790001},
+	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
+	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
+	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
+	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
+	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
+	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
+	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
+	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
+	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
+	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
+	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
+	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
+	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
+	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
+	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
+	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
+	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
+	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
+	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
+	{0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00039c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001a3f1}, {0x0b, 0x00014787},
+	{0x0c, 0x000896fe}, {0x0d, 0x0000e02c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00030355},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0000024f},
+	{0x1f, 0x00000000}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x00057730},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f474},
+	{0x15, 0x0004f477}, {0x15, 0x0008f455},
+	{0x15, 0x000cf455}, {0x16, 0x00000339},
+	{0x16, 0x00040339}, {0x16, 0x00080339},
+	{0x16, 0x000c0366}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00000003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00000247}, {0x1f, 0x00000000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00010255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f424},
+	{0x15, 0x0004f424}, {0x15, 0x0008f424},
+	{0x15, 0x000cf424}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radiob_2t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287af}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x00014297},
+	{0x13, 0x00010295}, {0x13, 0x0000c298},
+	{0x13, 0x0000819c}, {0x13, 0x000040a8},
+	{0x13, 0x0000001c}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f424},
+	{0x15, 0x0004f424}, {0x15, 0x0008f424},
+	{0x15, 0x000cf424}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radioa_1t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00010255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f405},
+	{0x15, 0x0004f405}, {0x15, 0x0008f405},
+	{0x15, 0x000cf405}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb0}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e529},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00000255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x0000083c},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000977c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x000d8000}, {0x12, 0x00090000},
+	{0x12, 0x00051000}, {0x12, 0x00012000},
+	{0x13, 0x00028fb4}, {0x13, 0x00024fa8},
+	{0x13, 0x000207a4}, {0x13, 0x0001c3b0},
+	{0x13, 0x000183a4}, {0x13, 0x00014398},
+	{0x13, 0x000101a4}, {0x13, 0x0000c198},
+	{0x13, 0x000080a4}, {0x13, 0x00004098},
+	{0x13, 0x00000000}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f405},
+	{0x15, 0x0004f405}, {0x15, 0x0008f405},
+	{0x15, 0x000cf405}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = {
+	{	/* RF_A */
+		.hssiparm1 = REG_FPGA0_XA_HSSI_PARM1,
+		.hssiparm2 = REG_FPGA0_XA_HSSI_PARM2,
+		.lssiparm = REG_FPGA0_XA_LSSI_PARM,
+		.hspiread = REG_HSPI_XA_READBACK,
+		.lssiread = REG_FPGA0_XA_LSSI_READBACK,
+		.rf_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL,
+	},
+	{	/* RF_B */
+		.hssiparm1 = REG_FPGA0_XB_HSSI_PARM1,
+		.hssiparm2 = REG_FPGA0_XB_HSSI_PARM2,
+		.lssiparm = REG_FPGA0_XB_LSSI_PARM,
+		.hspiread = REG_HSPI_XB_READBACK,
+		.lssiread = REG_FPGA0_XB_LSSI_READBACK,
+		.rf_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL,
+	},
+};
+
+static const u32 rtl8723au_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = {
+	REG_OFDM0_XA_RX_IQ_IMBALANCE,
+	REG_OFDM0_XB_RX_IQ_IMBALANCE,
+	REG_OFDM0_ENERGY_CCA_THRES,
+	REG_OFDM0_AGCR_SSI_TABLE,
+	REG_OFDM0_XA_TX_IQ_IMBALANCE,
+	REG_OFDM0_XB_TX_IQ_IMBALANCE,
+	REG_OFDM0_XC_TX_AFE,
+	REG_OFDM0_XD_TX_AFE,
+	REG_OFDM0_RX_IQ_EXT_ANTA
+};
+
+static u8 rtl8xxxu_read8(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u8 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = priv->usb_buf.val8;
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)   = 0x%02x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static u16 rtl8xxxu_read16(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u16 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = le16_to_cpu(priv->usb_buf.val16);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)  = 0x%04x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static u32 rtl8xxxu_read32(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u32 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = le32_to_cpu(priv->usb_buf.val32);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)  = 0x%08x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static int rtl8xxxu_write8(struct rtl8xxxu_priv *priv, u16 addr, u8 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val8 = val;
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%02x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int rtl8xxxu_write16(struct rtl8xxxu_priv *priv, u16 addr, u16 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val16 = cpu_to_le16(val);
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%04x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int rtl8xxxu_write32(struct rtl8xxxu_priv *priv, u16 addr, u32 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val32 = cpu_to_le32(val);
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%08x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int
+rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, buf, len, RTW_USB_CONTROL_MSG_TIMEOUT);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = %p, len 0x%02x\n",
+			 __func__, addr, buf, len);
+	return ret;
+}
+
+static int
+rtl8xxxu_slow_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
+{
+	u32 blocksize = sizeof(u32);
+	u32 *buf4 = (u32 *)buf;
+	int i, offset, count, remainder;
+
+	count = len / blocksize;
+	remainder = len % blocksize;
+
+	for (i = 0; i < count; i++) {
+		offset = i * blocksize;
+		rtl8xxxu_write32(priv, (REG_FW_START_ADDRESS + offset),
+				 buf4[i]);
+	}
+
+	if (remainder) {
+		offset = count * blocksize;
+		buf += offset;
+		for (i = 0; i < remainder; i++) {
+			rtl8xxxu_write8(priv, (REG_FW_START_ADDRESS +
+					       offset + i), *(buf + i));
+		}
+	}
+
+	return len;
+}
+
+static u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv,
+			       enum rtl8xxxu_rfpath path, u8 reg)
+{
+	u32 hssia, val32, retval;
+
+	hssia = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+	if (path != RF_A)
+		val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm2);
+	else
+		val32 = hssia;
+
+	val32 &= ~FPGA0_HSSI_PARM2_ADDR_MASK;
+	val32 |= (reg << FPGA0_HSSI_PARM2_ADDR_SHIFT);
+	val32 |= FPGA0_HSSI_PARM2_EDGE_READ;
+	hssia &= ~FPGA0_HSSI_PARM2_EDGE_READ;
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
+
+	udelay(10);
+
+	rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].hssiparm2, val32);
+	udelay(100);
+
+	hssia |= FPGA0_HSSI_PARM2_EDGE_READ;
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
+	udelay(10);
+
+	val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm1);
+	if (val32 & FPGA0_HSSI_PARM1_PI)
+		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hspiread);
+	else
+		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].lssiread);
+
+	retval &= 0xfffff;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_READ)
+		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
+			 __func__, reg, retval);
+	return retval;
+}
+
+static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
+				enum rtl8xxxu_rfpath path, u8 reg, u32 data)
+{
+	int ret, retval;
+	u32 dataaddr;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_WRITE)
+		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
+			 __func__, reg, data);
+
+	data &= FPGA0_LSSI_PARM_DATA_MASK;
+	dataaddr = (reg << FPGA0_LSSI_PARM_ADDR_SHIFT) | data;
+
+	/* Use XB for path B */
+	ret = rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].lssiparm, dataaddr);
+	if (ret != sizeof(dataaddr))
+		retval = -EIO;
+	else
+		retval = 0;
+
+	udelay(1);
+
+	return retval;
+}
+
+static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c)
+{
+	struct device *dev = &priv->udev->dev;
+	int mbox_nr, retry, retval = 0;
+	int mbox_reg, mbox_ext_reg;
+	u8 val8;
+
+	mutex_lock(&priv->h2c_mutex);
+
+	mbox_nr = priv->next_mbox;
+	mbox_reg = REG_HMBOX_0 + (mbox_nr * 4);
+	mbox_ext_reg = REG_HMBOX_EXT_0 + (mbox_nr * 2);
+
+	/*
+	 * MBOX ready?
+	 */
+	retry = 100;
+	do {
+		val8 = rtl8xxxu_read8(priv, REG_HMTFR);
+		if (!(val8 & BIT(mbox_nr)))
+			break;
+	} while (retry--);
+
+	if (!retry) {
+		dev_dbg(dev, "%s: Mailbox busy\n", __func__);
+		retval = -EBUSY;
+		goto error;
+	}
+
+	/*
+	 * Need to swap as it's being swapped again by rtl8xxxu_write16/32()
+	 */
+	if (h2c->cmd.cmd & H2C_EXT) {
+		rtl8xxxu_write16(priv, mbox_ext_reg,
+				 le16_to_cpu(h2c->raw.ext));
+		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
+			dev_info(dev, "H2C_EXT %04x\n",
+				 le16_to_cpu(h2c->raw.ext));
+	}
+	rtl8xxxu_write32(priv, mbox_reg, le32_to_cpu(h2c->raw.data));
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
+		dev_info(dev, "H2C %08x\n", le32_to_cpu(h2c->raw.data));
+
+	priv->next_mbox = (mbox_nr + 1) % H2C_MAX_MBOX;
+
+error:
+	mutex_unlock(&priv->h2c_mutex);
+	return retval;
+}
+
+static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u32 val32;
+
+	val8 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
+	val8 |= BIT(0) | BIT(3);
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, val8);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
+	val32 &= ~(BIT(4) | BIT(5));
+	val32 |= BIT(3);
+	if (priv->rf_paths == 2) {
+		val32 &= ~(BIT(20) | BIT(21));
+		val32 |= BIT(19);
+	}
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	val32 &= ~OFDM_RF_PATH_TX_MASK;
+	if (priv->tx_paths == 2)
+		val32 |= OFDM_RF_PATH_TX_A | OFDM_RF_PATH_TX_B;
+	else if (priv->rtlchip == 0x8192c || priv->rtlchip == 0x8191c)
+		val32 |= OFDM_RF_PATH_TX_B;
+	else
+		val32 |= OFDM_RF_PATH_TX_A;
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 &= ~FPGA_RF_MODE_JAPAN;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x63db25a0);
+	else
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x631b25a0);
+
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x32d95);
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x32d95);
+
+#if 0
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE3);
+	rtl8xxxu_write8(priv, REG_APSD_CTRL, 0x00);
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE2);
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xE3);
+#endif
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
+}
+
+static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv)
+{
+	u8 sps0;
+	u32 val32;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	sps0 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
+
+	/* RF RX code for preamble power saving */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
+	val32 &= ~(BIT(3) | BIT(4) | BIT(5));
+	if (priv->rf_paths == 2)
+		val32 &= ~(BIT(19) | BIT(20) | BIT(21));
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
+
+	/* Disable TX for four paths */
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	val32 &= ~OFDM_RF_PATH_TX_MASK;
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+	/* Enable power saving */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 |= FPGA_RF_MODE_JAPAN;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	/* AFE control register to power down bits [30:22] */
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00db25a0);
+	else
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x001b25a0);
+
+	/* Power down RF module */
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0);
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0);
+
+	sps0 &= ~(BIT(0) | BIT(3));
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, sps0);
+}
+
+
+static void rtl8723a_stop_tx_beacon(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
+	val8 &= ~BIT(6);
+	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
+
+	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 1, 0x64);
+	val8 = rtl8xxxu_read8(priv, REG_TBTT_PROHIBIT + 2);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8);
+}
+
+
+/*
+ * The rtl8723a has 3 channel groups for it's efuse settings. It only
+ * supports the 2.4GHz band, so channels 1 - 14:
+ *  group 0: channels 1 - 3
+ *  group 1: channels 4 - 9
+ *  group 2: channels 10 - 14
+ *
+ * Note: We index from 0 in the code
+ */
+static int rtl8723a_channel_to_group(int channel)
+{
+	int group;
+
+	if (channel < 4)
+		group = 0;
+	else if (channel < 10)
+		group = 1;
+	else
+		group = 2;
+
+	return group;
+}
+
+static void rtl8723au_config_channel(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u32 val32, rsr;
+	u8 val8, opmode;
+	bool ht = true;
+	int sec_ch_above;
+	int i;
+
+	for (i = RF_A; i < priv->rf_paths; i++) {
+		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
+		val32 &= ~MODE_AG_CHANNEL_MASK;
+		val32 |= hw->conf.chandef.chan->hw_value;
+		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
+	}
+
+	opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE);
+	rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+
+	switch (hw->conf.chandef.width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		ht = false;
+	case NL80211_CHAN_WIDTH_20:
+		opmode |= BW_OPMODE_20MHZ;
+		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+		val32 &= ~FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
+		val32 &= ~FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
+		val32 |= FPGA0_ANALOG2_20MHZ;
+		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
+		break;
+	case NL80211_CHAN_WIDTH_40:
+		if (hw->conf.chandef.center_freq1 >
+		    hw->conf.chandef.chan->center_freq)
+			sec_ch_above = 1;
+		else
+			sec_ch_above = 0;
+
+		opmode &= ~BW_OPMODE_20MHZ;
+		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
+		rsr &= ~RSR_RSC_BANDWIDTH_40M;
+		if (sec_ch_above)
+			rsr |= RSR_RSC_UPPER_SUB_CHANNEL;
+		else
+			rsr |= RSR_RSC_LOWER_SUB_CHANNEL;
+		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+		val32 |= FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
+		val32 |= FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
+
+		/*
+		 * Set Control channel to upper or lower. These settings
+		 * are required only for 40MHz
+		 */
+		val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM);
+		val32 &= ~CCK0_SIDEBAND;
+		if (!sec_ch_above)
+			val32 |= CCK0_SIDEBAND;
+		rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
+		val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */
+		if (sec_ch_above)
+			val32 |= OFDM_LSTF_PRIME_CH_LOW;
+		else
+			val32 |= OFDM_LSTF_PRIME_CH_HIGH;
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
+		val32 &= ~FPGA0_ANALOG2_20MHZ;
+		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
+		val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL);
+		if (sec_ch_above)
+			val32 |= FPGA0_PS_UPPER_CHANNEL;
+		else
+			val32 |= FPGA0_PS_LOWER_CHANNEL;
+		rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
+		break;
+
+	default:
+		break;
+	}
+
+	if (ht)
+		val8 = 0x0e;
+	else
+		val8 = 0x0a;
+
+	rtl8xxxu_write8(priv, REG_SIFS_CCK + 1, val8);
+	rtl8xxxu_write8(priv, REG_SIFS_OFDM + 1, val8);
+
+	rtl8xxxu_write16(priv, REG_R2T_SIFS, 0x0808);
+	rtl8xxxu_write16(priv, REG_T2T_SIFS, 0x0a0a);
+
+	for (i = RF_A; i < priv->rf_paths; i++) {
+		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
+		if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40)
+			val32 &= ~MODE_AG_CHANNEL_20MHZ;
+		else
+			val32 |= MODE_AG_CHANNEL_20MHZ;
+		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
+	}
+}
+
+static void
+rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
+{
+	u8 cck[RTL8723A_MAX_RF_PATHS], ofdm[RTL8723A_MAX_RF_PATHS];
+	u8 ofdmbase[RTL8723A_MAX_RF_PATHS], mcsbase[RTL8723A_MAX_RF_PATHS];
+	u32 val32, ofdm_a, ofdm_b, mcs_a, mcs_b;
+	u8 val8;
+	int group, i;
+
+	group = rtl8723a_channel_to_group(channel);
+
+	cck[0] = priv->cck_tx_power_index_A[group];
+	ofdm[0] = priv->ht40_1s_tx_power_index_A[group];
+
+	if (priv->rf_paths > 1) {
+		cck[1] = priv->cck_tx_power_index_B[group];
+		ofdm[1] = priv->ht40_1s_tx_power_index_B[group];
+	} else {
+		cck[1] = 0;
+		ofdm[1] = 0;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
+		dev_info(&priv->udev->dev,
+			 "%s: Setting TX power CCK A: %02x, "
+			 "CCK B: %02x, OFDM A: %02x, OFDM B: %02x\n",
+			 __func__, cck[0], cck[1], ofdm[0], ofdm[1]);
+
+	for (i = 0; i < RTL8723A_MAX_RF_PATHS; i++) {
+		if (cck[i] > RF6052_MAX_TX_PWR)
+			cck[i] = RF6052_MAX_TX_PWR;
+		if (ofdm[i] > RF6052_MAX_TX_PWR)
+			ofdm[i] = RF6052_MAX_TX_PWR;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32);
+	val32 &= 0xffff00ff;
+	val32 |= (cck[0] << 8);
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+	val32 &= 0xff;
+	val32 |= ((cck[0] << 8) | (cck[0] << 16) | (cck[0] << 24));
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+	val32 &= 0xffffff00;
+	val32 |= cck[1];
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK1_55_MCS32);
+	val32 &= 0xff;
+	val32 |= ((cck[1] << 8) | (cck[1] << 16) | (cck[1] << 24));
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK1_55_MCS32, val32);
+
+	ofdmbase[0] = ofdm[0] +	priv->ofdm_tx_power_index_diff[group].a;
+	mcsbase[0] = ofdm[0];
+	if (!ht40)
+		mcsbase[0] += priv->ht20_tx_power_index_diff[group].a;
+
+	ofdmbase[1] = ofdm[1] +	priv->ofdm_tx_power_index_diff[group].b;
+	mcsbase[1] = ofdm[1];
+	if (!ht40)
+		mcsbase[1] += priv->ht20_tx_power_index_diff[group].b;
+
+	ofdm_a = ofdmbase[0] | ofdmbase[0] << 8 |
+		ofdmbase[0] << 16 | ofdmbase[0] << 24;
+	ofdm_b = ofdmbase[1] | ofdmbase[1] << 8 |
+		ofdmbase[1] << 16 | ofdmbase[1] << 24;
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm_b);
+
+	mcs_a = mcsbase[0] | mcsbase[0] << 8 |
+		mcsbase[0] << 16 | mcsbase[0] << 24;
+	mcs_b = mcsbase[1] | mcsbase[1] << 8 |
+		mcsbase[1] << 16 | mcsbase[1] << 24;
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs_a);
+	for (i = 0; i < 3; i++) {
+		if (i != 2)
+			val8 = (mcsbase[0] > 8) ? (mcsbase[0] - 8) : 0;
+		else
+			val8 = (mcsbase[0] > 6) ? (mcsbase[0] - 6) : 0;
+		rtl8xxxu_write8(priv, REG_OFDM0_XC_TX_IQ_IMBALANCE + i, val8);
+	}
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs_b);
+	for (i = 0; i < 3; i++) {
+		if (i != 2)
+			val8 = (mcsbase[1] > 8) ? (mcsbase[1] - 8) : 0;
+		else
+			val8 = (mcsbase[1] > 6) ? (mcsbase[1] - 6) : 0;
+		rtl8xxxu_write8(priv, REG_OFDM0_XD_TX_IQ_IMBALANCE + i, val8);
+	}
+}
+
+static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
+				  enum nl80211_iftype linktype)
+{
+	u16 val8;
+
+	val8 = rtl8xxxu_read16(priv, REG_MSR);
+	val8 &= ~MSR_LINKTYPE_MASK;
+
+	switch (linktype) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		val8 |= MSR_LINKTYPE_NONE;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		val8 |= MSR_LINKTYPE_ADHOC;
+		break;
+	case NL80211_IFTYPE_STATION:
+		val8 |= MSR_LINKTYPE_STATION;
+		break;
+	case NL80211_IFTYPE_AP:
+		val8 |= MSR_LINKTYPE_AP;
+		break;
+	default:
+		goto out;
+	}
+
+	rtl8xxxu_write8(priv, REG_MSR, val8);
+out:
+	return;
+}
+
+static void
+rtl8xxxu_set_retry(struct rtl8xxxu_priv *priv, u16 short_retry, u16 long_retry)
+{
+	u16 val16;
+
+	val16 = ((short_retry << RETRY_LIMIT_SHORT_SHIFT) &
+		 RETRY_LIMIT_SHORT_MASK) |
+		((long_retry << RETRY_LIMIT_LONG_SHIFT) &
+		 RETRY_LIMIT_LONG_MASK);
+
+	rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
+}
+
+static void
+rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm)
+{
+	u16 val16;
+
+	val16 = ((cck << SPEC_SIFS_CCK_SHIFT) & SPEC_SIFS_CCK_MASK) |
+		((ofdm << SPEC_SIFS_OFDM_SHIFT) & SPEC_SIFS_OFDM_MASK);
+
+	rtl8xxxu_write16(priv, REG_SPEC_SIFS, val16);
+}
+
+static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	char *cut;
+
+	switch (priv->chip_cut) {
+	case 0:
+		cut = "A";
+		break;
+	case 1:
+		cut = "B";
+		break;
+	default:
+		cut = "unknown";
+	}
+
+	dev_info(dev,
+		 "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n",
+		 priv->chip_name, cut, priv->vendor_umc ? "UMC" : "TSMC",
+		 priv->tx_paths, priv->rx_paths, priv->ep_tx_count,
+		 priv->has_wifi, priv->has_bluetooth, priv->has_gps,
+		 priv->hi_pa);
+
+	dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr);
+}
+
+static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	u32 val32, bonding;
+	u16 val16;
+
+	val32 = rtl8xxxu_read32(priv, REG_SYS_CFG);
+	priv->chip_cut = (val32 & SYS_CFG_CHIP_VERSION_MASK) >>
+		SYS_CFG_CHIP_VERSION_SHIFT;
+	if (val32 & SYS_CFG_TRP_VAUX_EN) {
+		dev_info(dev, "Unsupported test chip\n");
+		return -ENOTSUPP;
+	}
+
+	if (val32 & SYS_CFG_BT_FUNC) {
+		sprintf(priv->chip_name, "8723AU");
+		priv->rf_paths = 1;
+		priv->rx_paths = 1;
+		priv->tx_paths = 1;
+		priv->rtlchip = 0x8723a;
+
+		val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL);
+		if (val32 & MULTI_WIFI_FUNC_EN)
+			priv->has_wifi = 1;
+		if (val32 & MULTI_BT_FUNC_EN)
+			priv->has_bluetooth = 1;
+		if (val32 & MULTI_GPS_FUNC_EN)
+			priv->has_gps = 1;
+	} else if (val32 & SYS_CFG_TYPE_ID) {
+		bonding = rtl8xxxu_read32(priv, REG_HPON_FSM);
+		bonding &= HPON_FSM_BONDING_MASK;
+		if (bonding == HPON_FSM_BONDING_1T2R) {
+			sprintf(priv->chip_name, "8191CU");
+			priv->rf_paths = 2;
+			priv->rx_paths = 2;
+			priv->tx_paths = 1;
+			priv->rtlchip = 0x8191c;
+		} else {
+			sprintf(priv->chip_name, "8192CU");
+			priv->rf_paths = 2;
+			priv->rx_paths = 2;
+			priv->tx_paths = 2;
+			priv->rtlchip = 0x8192c;
+		}
+		priv->has_wifi = 1;
+	} else {
+		sprintf(priv->chip_name, "8188CU");
+		priv->rf_paths = 1;
+		priv->rx_paths = 1;
+		priv->tx_paths = 1;
+		priv->rtlchip = 0x8188c;
+		priv->has_wifi = 1;
+	}
+
+	if (val32 & SYS_CFG_VENDOR_ID)
+		priv->vendor_umc = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS);
+	priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28;
+
+	val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX);
+	if (val16 & NORMAL_SIE_EP_TX_HIGH_MASK) {
+		priv->ep_tx_high_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	if (val16 & NORMAL_SIE_EP_TX_NORMAL_MASK) {
+		priv->ep_tx_normal_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	if (val16 & NORMAL_SIE_EP_TX_LOW_MASK) {
+		priv->ep_tx_low_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	/*
+	 * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX
+	 */
+	if (!priv->ep_tx_count) {
+		switch (priv->nr_out_eps) {
+		case 3:
+			priv->ep_tx_low_queue = 1;
+			priv->ep_tx_count++;
+		case 2:
+			priv->ep_tx_normal_queue = 1;
+			priv->ep_tx_count++;
+		case 1:
+			priv->ep_tx_high_queue = 1;
+			priv->ep_tx_count++;
+			break;
+		default:
+			dev_info(dev, "Unsupported USB TX end-points\n");
+			return -ENOTSUPP;
+		}
+	}
+
+	return 0;
+}
+
+static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
+{
+	if (priv->efuse_wifi.efuse8723.rtl_id != cpu_to_le16(0x8129))
+		return -EINVAL;
+
+	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723.mac_addr);
+
+	memcpy(priv->cck_tx_power_index_A,
+	       priv->efuse_wifi.efuse8723.cck_tx_power_index_A,
+	       sizeof(priv->cck_tx_power_index_A));
+	memcpy(priv->cck_tx_power_index_B,
+	       priv->efuse_wifi.efuse8723.cck_tx_power_index_B,
+	       sizeof(priv->cck_tx_power_index_B));
+
+	memcpy(priv->ht40_1s_tx_power_index_A,
+	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_A,
+	       sizeof(priv->ht40_1s_tx_power_index_A));
+	memcpy(priv->ht40_1s_tx_power_index_B,
+	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_B,
+	       sizeof(priv->ht40_1s_tx_power_index_B));
+
+	memcpy(priv->ht20_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8723.ht20_tx_power_index_diff,
+	       sizeof(priv->ht20_tx_power_index_diff));
+	memcpy(priv->ofdm_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8723.ofdm_tx_power_index_diff,
+	       sizeof(priv->ofdm_tx_power_index_diff));
+
+	memcpy(priv->ht40_max_power_offset,
+	       priv->efuse_wifi.efuse8723.ht40_max_power_offset,
+	       sizeof(priv->ht40_max_power_offset));
+	memcpy(priv->ht20_max_power_offset,
+	       priv->efuse_wifi.efuse8723.ht20_max_power_offset,
+	       sizeof(priv->ht20_max_power_offset));
+
+	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
+		 priv->efuse_wifi.efuse8723.vendor_name);
+	dev_info(&priv->udev->dev, "Product: %.41s\n",
+		 priv->efuse_wifi.efuse8723.device_name);
+	return 0;
+}
+
+static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
+{
+	int i;
+
+	if (priv->efuse_wifi.efuse8192.rtl_id != cpu_to_le16(0x8129))
+		return -EINVAL;
+
+	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192.mac_addr);
+
+	memcpy(priv->cck_tx_power_index_A,
+	       priv->efuse_wifi.efuse8192.cck_tx_power_index_A,
+	       sizeof(priv->cck_tx_power_index_A));
+	memcpy(priv->cck_tx_power_index_B,
+	       priv->efuse_wifi.efuse8192.cck_tx_power_index_B,
+	       sizeof(priv->cck_tx_power_index_B));
+
+	memcpy(priv->ht40_1s_tx_power_index_A,
+	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_A,
+	       sizeof(priv->ht40_1s_tx_power_index_A));
+	memcpy(priv->ht40_1s_tx_power_index_B,
+	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_B,
+	       sizeof(priv->ht40_1s_tx_power_index_B));
+	memcpy(priv->ht40_2s_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ht40_2s_tx_power_index_diff,
+	       sizeof(priv->ht40_2s_tx_power_index_diff));
+
+	memcpy(priv->ht20_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ht20_tx_power_index_diff,
+	       sizeof(priv->ht20_tx_power_index_diff));
+	memcpy(priv->ofdm_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ofdm_tx_power_index_diff,
+	       sizeof(priv->ofdm_tx_power_index_diff));
+
+	memcpy(priv->ht40_max_power_offset,
+	       priv->efuse_wifi.efuse8192.ht40_max_power_offset,
+	       sizeof(priv->ht40_max_power_offset));
+	memcpy(priv->ht20_max_power_offset,
+	       priv->efuse_wifi.efuse8192.ht20_max_power_offset,
+	       sizeof(priv->ht20_max_power_offset));
+
+	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
+		 priv->efuse_wifi.efuse8192.vendor_name);
+	dev_info(&priv->udev->dev, "Product: %.20s\n",
+		 priv->efuse_wifi.efuse8192.device_name);
+
+	if (priv->efuse_wifi.efuse8192.rf_regulatory & 0x20) {
+		sprintf(priv->chip_name, "8188RU");
+		priv->hi_pa = 1;
+	}
+
+	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02x bytes):\n",
+		 __func__, (int)sizeof(struct rtl8192cu_efuse));
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
+		unsigned char *raw = priv->efuse_wifi.raw;
+
+		for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) {
+			dev_info(&priv->udev->dev, "%02x: "
+				 "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+				 raw[i], raw[i + 1], raw[i + 2],
+				 raw[i + 3], raw[i + 4], raw[i + 5],
+				 raw[i + 6], raw[i + 7]);
+		}
+	}
+	return 0;
+}
+
+static int
+rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data)
+{
+	int i;
+	u8 val8;
+	u32 val32;
+
+	/* Write Address */
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 1, offset & 0xff);
+	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 2);
+	val8 &= 0xfc;
+	val8 |= (offset >> 8) & 0x03;
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 2, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 3);
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 3, val8 & 0x7f);
+
+	/* Poll for data read */
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+	for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+		if (val32 & BIT(31))
+			break;
+	}
+
+	if (i == RTL8XXXU_MAX_REG_POLL)
+		return -EIO;
+
+	udelay(50);
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+
+	*data = val32 & 0xff;
+	return 0;
+}
+
+static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int i, ret = 0;
+	u8 val8, word_mask, header, extheader;
+	u16 val16, efuse_addr, offset;
+	u32 val32;
+
+	val16 = rtl8xxxu_read16(priv, REG_9346CR);
+	if (val16 & EEPROM_ENABLE)
+		priv->has_eeprom = 1;
+	if (val16 & EEPROM_BOOT)
+		priv->boot_eeprom = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST);
+	val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT;
+	rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32);
+
+	dev_dbg(dev, "Booting from %s\n",
+		priv->boot_eeprom ? "EEPROM" : "EFUSE");
+
+	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_ENABLE);
+
+	/*  1.2V Power: From VDDON with Power Cut(0x0000[15]), default valid */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
+	if (!(val16 & SYS_ISO_PWC_EV12V)) {
+		val16 |= SYS_ISO_PWC_EV12V;
+		rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
+	}
+	/*  Reset: 0x0000[28], default valid */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	if (!(val16 & SYS_FUNC_ELDR)) {
+		val16 |= SYS_FUNC_ELDR;
+		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+	}
+
+	/*
+	 * Clock: Gated(0x0008[5]) 8M(0x0008[1]) clock from ANA, default valid
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR);
+	if (!(val16 & SYS_CLK_LOADER_ENABLE) || !(val16 & SYS_CLK_ANA8M)) {
+		val16 |= (SYS_CLK_LOADER_ENABLE | SYS_CLK_ANA8M);
+		rtl8xxxu_write16(priv, REG_SYS_CLKR, val16);
+	}
+
+	/* Default value is 0xff */
+	memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN_8723A);
+
+	efuse_addr = 0;
+	while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) {
+		ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &header);
+		if (ret || header == 0xff)
+			goto exit;
+
+		if ((header & 0x1f) == 0x0f) {	/* extended header */
+			offset = (header & 0xe0) >> 5;
+
+			ret = rtl8xxxu_read_efuse8(priv, efuse_addr++,
+						   &extheader);
+			if (ret)
+				goto exit;
+			/* All words disabled */
+			if ((extheader & 0x0f) == 0x0f)
+				continue;
+
+			offset |= ((extheader & 0xf0) >> 1);
+			word_mask = extheader & 0x0f;
+		} else {
+			offset = (header >> 4) & 0x0f;
+			word_mask = header & 0x0f;
+		}
+
+		if (offset < EFUSE_MAX_SECTION_8723A) {
+			u16 map_addr;
+			/* Get word enable value from PG header */
+
+			/* We have 8 bits to indicate validity */
+			map_addr = offset * 8;
+			if (map_addr >= EFUSE_MAP_LEN_8723A) {
+				dev_warn(dev, "%s: Illegal map_addr (%04x), "
+					 "efuse corrupt!\n",
+					 __func__, map_addr);
+				ret = -EINVAL;
+				goto exit;
+			}
+			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+				/* Check word enable condition in the section */
+				if (!(word_mask & BIT(i))) {
+					ret = rtl8xxxu_read_efuse8(priv,
+								   efuse_addr++,
+								   &val8);
+					if (ret)
+						goto exit;
+					priv->efuse_wifi.raw[map_addr++] = val8;
+
+					ret = rtl8xxxu_read_efuse8(priv,
+								   efuse_addr++,
+								   &val8);
+					if (ret)
+						goto exit;
+					priv->efuse_wifi.raw[map_addr++] = val8;
+				} else
+					map_addr += 2;
+			}
+		} else {
+			dev_warn(dev,
+				 "%s: Illegal offset (%04x), efuse corrupt!\n",
+				 __func__, offset);
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+
+exit:
+	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_DISABLE);
+
+	return ret;
+}
+
+static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int ret = 0, i;
+	u32 val32;
+
+	/* Poll checksum report */
+	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+		if (val32 & MCU_FW_DL_CSUM_REPORT)
+			break;
+	}
+
+	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
+		dev_warn(dev, "Firmware checksum poll timed out\n");
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+	val32 |= MCU_FW_DL_READY;
+	val32 &= ~MCU_WINT_INIT_READY;
+	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32);
+
+	/* Wait for firmware to become ready */
+	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+		if (val32 & MCU_WINT_INIT_READY)
+			break;
+
+		udelay(100);
+	}
+
+	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
+		dev_warn(dev, "Firmware failed to start\n");
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
+{
+	int pages, remainder, i, ret;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	u8 *fwptr;
+
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1);
+	val8 |= 4;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, val8);
+
+	/* 8051 enable */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE);
+
+	/* MCU firmware download enable */
+	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE);
+
+	/* 8051 reset */
+	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19));
+
+	/* Reset firmware download checksum */
+	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT);
+
+	pages = priv->fw_size / RTL_FW_PAGE_SIZE;
+	remainder = priv->fw_size % RTL_FW_PAGE_SIZE;
+
+	fwptr = priv->fw_data->data;
+
+	for (i = 0; i < pages; i++) {
+		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
+		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+
+		ret = priv->fops->writeN(priv, REG_FW_START_ADDRESS,
+					 fwptr, RTL_FW_PAGE_SIZE);
+		if (ret != RTL_FW_PAGE_SIZE) {
+			ret = -EAGAIN;
+			goto fw_abort;
+		}
+
+		fwptr += RTL_FW_PAGE_SIZE;
+	}
+
+	if (remainder) {
+		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
+		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+		ret = priv->fops->writeN(priv, REG_FW_START_ADDRESS,
+					 fwptr, remainder);
+		if (ret != remainder) {
+			ret = -EAGAIN;
+			goto fw_abort;
+		}
+	}
+
+	ret = 0;
+fw_abort:
+	/* MCU firmware download disable */
+	val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write16(priv, REG_MCU_FW_DL,
+			 val16 & (~MCU_FW_DL_ENABLE & 0xff));
+
+	return ret;
+}
+
+static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name)
+{
+	struct device *dev = &priv->udev->dev;
+	const struct firmware *fw;
+	int ret = 0;
+	u16 signature;
+
+	dev_info(dev, "%s: Loading firmware %s\n", DRIVER_NAME, fw_name);
+	if (request_firmware(&fw, fw_name, &priv->udev->dev)) {
+		dev_warn(dev, "request_firmware(%s) failed\n", fw_name);
+		ret = -EAGAIN;
+		goto exit;
+	}
+	if (!fw) {
+		dev_warn(dev, "Firmware data not available\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+	priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header);
+
+	signature = le16_to_cpu(priv->fw_data->signature);
+	switch (signature & 0xfff0) {
+	case 0x92c0:
+	case 0x88c0:
+	case 0x2300:
+		break;
+	default:
+		ret = -EINVAL;
+		dev_warn(dev, "%s: Invalid firmware signature: 0x%04x\n",
+			 __func__, signature);
+	}
+
+	dev_info(dev, "Firmware revision %i.%i (signature 0x%04x)\n",
+		 le16_to_cpu(priv->fw_data->major_version),
+		 priv->fw_data->minor_version, signature);
+
+exit:
+	release_firmware(fw);
+	return ret;
+}
+
+static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv)
+{
+	char *fw_name;
+	int ret;
+
+	switch (priv->chip_cut) {
+	case 0:
+		fw_name = "rtlwifi/rtl8723aufw_A.bin";
+		break;
+	case 1:
+		if (priv->enable_bluetooth)
+			fw_name = "rtlwifi/rtl8723aufw_B.bin";
+		else
+			fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = rtl8xxxu_load_firmware(priv, fw_name);
+	return ret;
+}
+
+static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv)
+{
+	char *fw_name;
+	int ret;
+
+	if (!priv->vendor_umc)
+		fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
+	else if (priv->chip_cut || priv->rtlchip == 0x8192c)
+		fw_name = "rtlwifi/rtl8192cufw_B.bin";
+	else
+		fw_name = "rtlwifi/rtl8192cufw_A.bin";
+
+	ret = rtl8xxxu_load_firmware(priv, fw_name);
+
+	return ret;
+}
+
+static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv)
+{
+	u16 val16;
+	int i = 100;
+
+	/* Inform 8051 to perform reset */
+	rtl8xxxu_write8(priv, REG_HMTFR + 3, 0x20);
+
+	for (i = 100; i > 0; i--) {
+		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+
+		if (!(val16 & SYS_FUNC_CPU_ENABLE)) {
+			dev_dbg(&priv->udev->dev,
+				"%s: Firmware self reset success!\n", __func__);
+			break;
+		}
+		udelay(50);
+	}
+
+	if (!i) {
+		/* Force firmware reset */
+		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+		val16 &= ~SYS_FUNC_CPU_ENABLE;
+		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+	}
+}
+
+static int
+rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array)
+{
+	int i, ret;
+	u16 reg;
+	u8 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xffff && val == 0xff)
+			break;
+
+		ret = rtl8xxxu_write8(priv, reg, val);
+		if (ret != 1) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize MAC\n");
+			return -EAGAIN;
+		}
+	}
+
+	rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a);
+
+	return 0;
+}
+
+static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_reg32val *array)
+{
+	int i, ret;
+	u16 reg;
+	u32 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xffff && val == 0xffffffff)
+			break;
+
+		ret = rtl8xxxu_write32(priv, reg, val);
+		if (ret != sizeof(val)) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize PHY\n");
+			return -EAGAIN;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+/*
+ * Most of this is black magic retrieved from the old rtl8723au driver
+ */
+static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
+{
+	u8 val8, ldoa15, ldov12d, lpldo, ldohci12;
+	u32 val32;
+
+	/*
+	 * Todo: The vendor driver maintains a table of PHY register
+	 *       addresses, which is initialized here. Do we need this?
+	 */
+
+	val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
+	udelay(2);
+	val8 |= AFE_PLL_320_ENABLE;
+	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
+	udelay(2);
+
+	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff);
+	udelay(2);
+
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	/* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */
+	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
+	val32 &= ~AFE_XTAL_RF_GATE;
+	if (priv->has_bluetooth)
+		val32 &= ~AFE_XTAL_BT_GATE;
+	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
+
+	/* 6. 0x1f[7:0] = 0x07 */
+	val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
+	rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
+
+	if (priv->hi_pa)
+		rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table);
+	else if (priv->tx_paths == 2)
+		rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table);
+	else
+		rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table);
+
+
+	if (priv->rtlchip == 0x8188c && priv->hi_pa &&
+	    priv->vendor_umc && priv->chip_cut == 1)
+		rtl8xxxu_write8(priv, REG_OFDM0_AGC_PARM1 + 2, 0x50);
+
+	if (priv->tx_paths == 1 && priv->rx_paths == 2) {
+		/*
+		 * For 1T2R boards, patch the registers.
+		 *
+		 * It looks like 8191/2 1T2R boards use path B for TX
+		 */
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO);
+		val32 &= ~(BIT(0) | BIT(1));
+		val32 |= BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO);
+		val32 &= ~0x300033;
+		val32 |= 0x200022;
+		rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
+		val32 &= 0xff000000;
+		val32 |= 0x45000000;
+		rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+		val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK);
+		val32 |= (OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B |
+			  OFDM_RF_PATH_TX_B);
+		rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGC_PARM1);
+		val32 &= ~(BIT(4) | BIT(5));
+		val32 |= BIT(4);
+		rtl8xxxu_write32(priv, REG_OFDM0_AGC_PARM1, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_RFON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_CCK_RFON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_BBON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_CCK_BBON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_RFON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_OFDM_RFON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_BBON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_OFDM_BBON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_TO_TX);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_TO_TX, val32);
+	}
+
+	if (priv->hi_pa)
+		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table);
+	else
+		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table);
+
+	if (priv->rtlchip == 0x8723a &&
+	    priv->efuse_wifi.efuse8723.version >= 0x01) {
+		val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);
+
+		val8 = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
+		val32 &= 0xff000fff;
+		val32 |= ((val8 | (val8 << 6)) << 12);
+
+		rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);
+	}
+
+	ldoa15 = LDOA15_ENABLE | LDOA15_OBUF;
+	ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT);
+	ldohci12 = 0x57;
+	lpldo = 1;
+	val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15;
+
+	rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32);
+
+	return 0;
+}
+
+static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv,
+				 struct rtl8xxxu_rfregval *array,
+				 enum rtl8xxxu_rfpath path)
+{
+	int i, ret;
+	u8 reg;
+	u32 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xff && val == 0xffffffff)
+			break;
+
+		switch (reg) {
+		case 0xfe:
+			msleep(50);
+			continue;
+		case 0xfd:
+			mdelay(5);
+			continue;
+		case 0xfc:
+			mdelay(1);
+			continue;
+		case 0xfb:
+			udelay(50);
+			continue;
+		case 0xfa:
+			udelay(5);
+			continue;
+		case 0xf9:
+			udelay(1);
+			continue;
+		}
+
+		reg &= 0x3f;
+
+		ret = rtl8xxxu_write_rfreg(priv, path, reg, val);
+		if (ret) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize RF\n");
+			return -EAGAIN;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv,
+				struct rtl8xxxu_rfregval *table,
+				enum rtl8xxxu_rfpath path)
+{
+	u32 val32;
+	u16 val16, rfsi_rfenv;
+	u16 reg_sw_ctrl, reg_int_oe, reg_hssi_parm2;
+
+	switch (path) {
+	case RF_A:
+		reg_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL;
+		reg_int_oe = REG_FPGA0_XA_RF_INT_OE;
+		reg_hssi_parm2 = REG_FPGA0_XA_HSSI_PARM2;
+		break;
+	case RF_B:
+		reg_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL;
+		reg_int_oe = REG_FPGA0_XB_RF_INT_OE;
+		reg_hssi_parm2 = REG_FPGA0_XB_HSSI_PARM2;
+		break;
+	default:
+		dev_err(&priv->udev->dev, "%s:Unsupported RF path %c\n",
+			__func__, path + 'A');
+		return -EINVAL;
+	}
+	/* For path B, use XB */
+	rfsi_rfenv = rtl8xxxu_read16(priv, reg_sw_ctrl);
+	rfsi_rfenv &= FPGA0_RF_RFENV;
+
+	/*
+	 * These two we might be able to optimize into one
+	 */
+	val32 = rtl8xxxu_read32(priv, reg_int_oe);
+	val32 |= BIT(20);	/* 0x10 << 16 */
+	rtl8xxxu_write32(priv, reg_int_oe, val32);
+	udelay(1);
+
+	val32 = rtl8xxxu_read32(priv, reg_int_oe);
+	val32 |= BIT(4);
+	rtl8xxxu_write32(priv, reg_int_oe, val32);
+	udelay(1);
+
+	/*
+	 * These two we might be able to optimize into one
+	 */
+	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
+	val32 &= ~FPGA0_HSSI_3WIRE_ADDR_LEN;
+	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
+	udelay(1);
+
+	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
+	val32 &= ~FPGA0_HSSI_3WIRE_DATA_LEN;
+	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
+	udelay(1);
+
+	rtl8xxxu_init_rf_regs(priv, table, path);
+
+	/* For path B, use XB */
+	val16 = rtl8xxxu_read16(priv, reg_sw_ctrl);
+	val16 &= ~FPGA0_RF_RFENV;
+	val16 |= rfsi_rfenv;
+	rtl8xxxu_write16(priv, reg_sw_ctrl, val16);
+
+	return 0;
+}
+
+static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data)
+{
+	int ret = -EBUSY;
+	int count = 0;
+	u32 value;
+
+	value = LLT_OP_WRITE | address << 8 | data;
+
+	rtl8xxxu_write32(priv, REG_LLT_INIT, value);
+
+	do {
+		value = rtl8xxxu_read32(priv, REG_LLT_INIT);
+		if ((value & LLT_OP_MASK) == LLT_OP_INACTIVE) {
+			ret = 0;
+			break;
+		}
+	} while (count++ < 20);
+
+	return ret;
+}
+
+static int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < last_tx_page; i++) {
+		ret = rtl8xxxu_llt_write(priv, i, i + 1);
+		if (ret)
+			goto exit;
+	}
+
+	ret = rtl8xxxu_llt_write(priv, last_tx_page, 0xff);
+	if (ret)
+		goto exit;
+
+	/* Mark remaining pages as a ring buffer */
+	for (i = last_tx_page + 1; i < 0xff; i++) {
+		ret = rtl8xxxu_llt_write(priv, i, (i + 1));
+		if (ret)
+			goto exit;
+	}
+
+	/*  Let last entry point to the start entry of ring buffer */
+	ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1);
+	if (ret)
+		goto exit;
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv)
+{
+	u16 val16, hi, lo;
+	u16 hiq, mgq, bkq, beq, viq, voq;
+	int hip, mgp, bkp, bep, vip, vop;
+	int ret = 0;
+
+	switch (priv->ep_tx_count) {
+	case 1:
+		if (priv->ep_tx_high_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+		} else if (priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_normal_queue) {
+			hi = TRXDMA_QUEUE_NORMAL;
+		} else {
+			hi = 0;
+			ret = -EINVAL;
+		}
+
+		hiq = hi;
+		mgq = hi;
+		bkq = hi;
+		beq = hi;
+		viq = hi;
+		voq = hi;
+
+		hip = 0;
+		mgp = 0;
+		bkp = 0;
+		bep = 0;
+		vip = 0;
+		vop = 0;
+		break;
+	case 2:
+		if (priv->ep_tx_high_queue && priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+			lo = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_normal_queue && priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_NORMAL;
+			lo = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_high_queue && priv->ep_tx_normal_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+			lo = TRXDMA_QUEUE_NORMAL;
+		} else {
+			ret = -EINVAL;
+			hi = 0;
+			lo = 0;
+		}
+
+		hiq = hi;
+		mgq = hi;
+		bkq = lo;
+		beq = lo;
+		viq = hi;
+		voq = hi;
+
+		hip = 0;
+		mgp = 0;
+		bkp = 1;
+		bep = 1;
+		vip = 0;
+		vop = 0;
+		break;
+	case 3:
+		beq = TRXDMA_QUEUE_LOW;
+		bkq = TRXDMA_QUEUE_LOW;
+		viq = TRXDMA_QUEUE_NORMAL;
+		voq = TRXDMA_QUEUE_HIGH;
+		mgq = TRXDMA_QUEUE_HIGH;
+		hiq = TRXDMA_QUEUE_HIGH;
+
+		hip = hiq ^ 3;
+		mgp = mgq ^ 3;
+		bkp = bkq ^ 3;
+		bep = beq ^ 3;
+		vip = viq ^ 3;
+		vop = viq ^ 3;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	/*
+	 * None of the vendor drivers are configuring the beacon
+	 * queue here .... why?
+	 */
+	if (!ret) {
+		val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL);
+		val16 &= 0x7;
+		val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) |
+			(viq << TRXDMA_CTRL_VIQ_SHIFT) |
+			(beq << TRXDMA_CTRL_BEQ_SHIFT) |
+			(bkq << TRXDMA_CTRL_BKQ_SHIFT) |
+			(mgq << TRXDMA_CTRL_MGQ_SHIFT) |
+			(hiq << TRXDMA_CTRL_HIQ_SHIFT);
+		rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16);
+
+		priv->pipe_out[TXDESC_QUEUE_VO] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[vop]);
+		priv->pipe_out[TXDESC_QUEUE_VI] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[vip]);
+		priv->pipe_out[TXDESC_QUEUE_BE] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[bep]);
+		priv->pipe_out[TXDESC_QUEUE_BK] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[bkp]);
+		priv->pipe_out[TXDESC_QUEUE_BEACON] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
+		priv->pipe_out[TXDESC_QUEUE_MGNT] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[mgp]);
+		priv->pipe_out[TXDESC_QUEUE_HIGH] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[hip]);
+		priv->pipe_out[TXDESC_QUEUE_CMD] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
+	}
+
+	return ret;
+}
+
+static void rtl8xxxu_fill_iqk_matrix_a(struct rtl8xxxu_priv *priv,
+				       bool iqk_ok, int result[][8],
+				       int candidate, bool tx_only)
+{
+	u32 oldval, x, tx0_a, reg;
+	int y, tx0_c;
+	u32 val32;
+
+	if (!iqk_ok)
+		return;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	oldval = val32 >> 22;
+
+	x = result[candidate][0];
+	if ((x & 0x00000200) != 0)
+		x = x | 0xfffffc00;
+	tx0_a = (x * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= tx0_a;
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(31);
+	if ((x * oldval >> 7) & 0x1)
+		val32 |= BIT(31);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	y = result[candidate][1];
+	if ((y & 0x00000200) != 0)
+		y = y | 0xfffffc00;
+	tx0_c = (y * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XC_TX_AFE);
+	val32 &= ~0xf0000000;
+	val32 |= (((tx0_c & 0x3c0) >> 6) << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_XC_TX_AFE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	val32 &= ~0x003f0000;
+	val32 |= ((tx0_c & 0x3f) << 16);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(29);
+	if ((y * oldval >> 7) & 0x1)
+		val32 |= BIT(29);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	if (tx_only) {
+		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
+		return;
+	}
+
+	reg = result[candidate][2];
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= (reg & 0x3ff);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
+
+	reg = result[candidate][3] & 0x3F;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
+	val32 &= ~0xfc00;
+	val32 |= ((reg << 10) & 0xfc00);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
+
+	reg = (result[candidate][3] >> 6) & 0xF;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_RX_IQ_EXT_ANTA);
+	val32 &= ~0xf0000000;
+	val32 |= (reg << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_RX_IQ_EXT_ANTA, val32);
+}
+
+static void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv,
+				       bool iqk_ok, int result[][8],
+				       int candidate, bool tx_only)
+{
+	u32 oldval, x, tx1_a, reg;
+	int y, tx1_c;
+	u32 val32;
+
+	if (!iqk_ok)
+		return;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	oldval = val32 >> 22;
+
+	x = result[candidate][4];
+	if ((x & 0x00000200) != 0)
+		x = x | 0xfffffc00;
+	tx1_a = (x * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= tx1_a;
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(27);
+	if ((x * oldval >> 7) & 0x1)
+		val32 |= BIT(27);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	y = result[candidate][5];
+	if ((y & 0x00000200) != 0)
+		y = y | 0xfffffc00;
+	tx1_c = (y * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XD_TX_AFE);
+	val32 &= ~0xf0000000;
+	val32 |= (((tx1_c & 0x3c0) >> 6) << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_XD_TX_AFE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	val32 &= ~0x003f0000;
+	val32 |= ((tx1_c & 0x3f) << 16);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(25);
+	if ((y * oldval >> 7) & 0x1)
+		val32 |= BIT(25);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	if (tx_only) {
+		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
+		return;
+	}
+
+	reg = result[candidate][6];
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= (reg & 0x3ff);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
+
+	reg = result[candidate][7] & 0x3f;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
+	val32 &= ~0xfc00;
+	val32 |= ((reg << 10) & 0xfc00);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
+
+	reg = (result[candidate][7] >> 6) & 0xf;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE);
+	val32 &= ~0x0000f000;
+	val32 |= (reg << 12);
+	rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32);
+}
+
+#define MAX_TOLERANCE		5
+
+static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv,
+					int result[][8], int c1, int c2)
+{
+	u32 i, j, diff, simubitmap, bound = 0;
+	int candidate[2] = {-1, -1};	/* for path A and path B */
+	bool retval = true;
+
+	if (priv->tx_paths > 1)
+		bound = 8;
+	else
+		bound = 4;
+
+	simubitmap = 0;
+
+	for (i = 0; i < bound; i++) {
+		diff = (result[c1][i] > result[c2][i]) ?
+			(result[c1][i] - result[c2][i]) :
+			(result[c2][i] - result[c1][i]);
+		if (diff > MAX_TOLERANCE) {
+			if ((i == 2 || i == 6) && !simubitmap) {
+				if (result[c1][i] + result[c1][i + 1] == 0)
+					candidate[(i / 4)] = c2;
+				else if (result[c2][i] + result[c2][i + 1] == 0)
+					candidate[(i / 4)] = c1;
+				else
+					simubitmap = simubitmap | (1 << i);
+			} else {
+				simubitmap = simubitmap | (1 << i);
+			}
+		}
+	}
+
+	if (simubitmap == 0) {
+		for (i = 0; i < (bound / 4); i++) {
+			if (candidate[i] >= 0) {
+				for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+					result[3][j] = result[candidate[i]][j];
+				retval = false;
+			}
+		}
+		return retval;
+	} else if (!(simubitmap & 0x0f)) {
+		/* path A OK */
+		for (i = 0; i < 4; i++)
+			result[3][i] = result[c1][i];
+	} else if (!(simubitmap & 0xf0) && priv->tx_paths > 1) {
+		/* path B OK */
+		for (i = 4; i < 8; i++)
+			result[3][i] = result[c1][i];
+	}
+
+	return false;
+}
+
+static void
+rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv, const u32 *reg, u32 *backup)
+{
+	int i;
+
+	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		backup[i] = rtl8xxxu_read8(priv, reg[i]);
+
+	backup[i] = rtl8xxxu_read32(priv, reg[i]);
+}
+
+static void rtl8xxxu_restore_mac_regs(struct rtl8xxxu_priv *priv,
+				      const u32 *reg, u32 *backup)
+{
+	int i;
+
+	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		rtl8xxxu_write8(priv, reg[i], backup[i]);
+
+	rtl8xxxu_write32(priv, reg[i], backup[i]);
+}
+
+static void rtl8xxxu_save_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
+			       u32 *backup, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		backup[i] = rtl8xxxu_read32(priv, regs[i]);
+}
+
+static void rtl8xxxu_restore_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
+				  u32 *backup, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		rtl8xxxu_write32(priv, regs[i], backup[i]);
+}
+
+
+static void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs,
+				  bool path_a_on)
+{
+	u32 path_on;
+	int i;
+
+	path_on = path_a_on ? 0x04db25a4 : 0x0b1b25a4;
+	if (priv->tx_paths == 1) {
+		path_on = 0x0bdb25a0;
+		rtl8xxxu_write32(priv, regs[0], 0x0b1b25a0);
+	} else {
+		rtl8xxxu_write32(priv, regs[0], path_on);
+	}
+
+	for (i = 1 ; i < RTL8XXXU_ADDA_REGS ; i++)
+		rtl8xxxu_write32(priv, regs[i], path_on);
+}
+
+static void rtl8xxxu_mac_calibration(struct rtl8xxxu_priv *priv,
+				     const u32 *regs, u32 *backup)
+{
+	int i = 0;
+
+	rtl8xxxu_write8(priv, regs[i], 0x3f);
+
+	for (i = 1 ; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(3)));
+
+	rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(5)));
+}
+
+static int rtl8xxxu_iqk_path_a(struct rtl8xxxu_priv *priv)
+{
+	u32 reg_eac, reg_e94, reg_e9c, reg_ea4, val32;
+	int result = 0;
+
+	/* path-A IQK setting */
+	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1f);
+	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1f);
+	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82140102);
+
+	val32 = (priv->rf_paths > 1) ? 0x28160202 :
+		/*IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202: */
+		0x28160502;
+	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, val32);
+
+	/* path-B IQK setting */
+	if (priv->rf_paths > 1) {
+		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x10008c22);
+		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x10008c22);
+		rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82140102);
+		rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28160202);
+	}
+
+	/* LO calibration setting */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x001028d1);
+
+	/* One shot, path A LOK & IQK */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
+	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+	mdelay(1);
+
+	/* Check failed */
+	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+	reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
+	reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
+	reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2);
+
+	if (!(reg_eac & BIT(28)) &&
+	    ((reg_e94 & 0x03ff0000) != 0x01420000) &&
+	    ((reg_e9c & 0x03ff0000) != 0x00420000))
+		result |= 0x01;
+	else	/* If TX not OK, ignore RX */
+		goto out;
+
+	/* If TX is OK, check whether RX is OK */
+	if (!(reg_eac & BIT(27)) &&
+	    ((reg_ea4 & 0x03ff0000) != 0x01320000) &&
+	    ((reg_eac & 0x03ff0000) != 0x00360000))
+		result |= 0x02;
+	else
+		dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n",
+			 __func__);
+out:
+	return result;
+}
+
+static int rtl8xxxu_iqk_path_b(struct rtl8xxxu_priv *priv)
+{
+	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	int result = 0;
+
+	/* One shot, path B LOK & IQK */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002);
+	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000);
+
+	mdelay(1);
+
+	/* Check failed */
+	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+	reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+	reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+	reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+	reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+
+	if (!(reg_eac & BIT(31)) &&
+	    ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
+	    ((reg_ebc & 0x03ff0000) != 0x00420000))
+		result |= 0x01;
+	else
+		goto out;
+
+	if (!(reg_eac & BIT(30)) &&
+	    (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) &&
+	    (((reg_ecc & 0x03ff0000) >> 16) != 0x36))
+		result |= 0x02;
+	else
+		dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n",
+			 __func__);
+out:
+	return result;
+}
+
+static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
+				     int result[][8], int t)
+{
+	struct device *dev = &priv->udev->dev;
+	u32 i, val32;
+	int path_a_ok, path_b_ok;
+	int retry = 2;
+	const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
+		REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
+		REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
+		REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
+		REG_TX_OFDM_BBON, REG_TX_TO_RX,
+		REG_TX_TO_TX, REG_RX_CCK,
+		REG_RX_OFDM, REG_RX_WAIT_RIFS,
+		REG_RX_TO_RX, REG_STANDBY,
+		REG_SLEEP, REG_PMPD_ANAEN
+	};
+	const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
+		REG_TXPAUSE, REG_BEACON_CTRL,
+		REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
+	};
+	const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
+		REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
+		REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
+		REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
+		REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE
+	};
+
+	/*
+	 * Note: IQ calibration must be performed after loading
+	 *       PHY_REG.txt , and radio_a, radio_b.txt
+	 */
+
+	if (t == 0) {
+		/* Save ADDA parameters, turn Path A ADDA on */
+		rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
+				   RTL8XXXU_ADDA_REGS);
+		rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+		rtl8xxxu_save_regs(priv, iqk_bb_regs,
+				   priv->bb_backup, RTL8XXXU_BB_REGS);
+	}
+
+	rtl8xxxu_path_adda_on(priv, adda_regs, true);
+
+	if (t == 0) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
+		if (val32 & FPGA0_HSSI_PARM1_PI)
+			priv->pi_enabled = 1;
+	}
+
+	if (!priv->pi_enabled) {
+		/* Switch BB to PI mode to do IQ Calibration. */
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
+		rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 &= ~FPGA_RF_MODE_CCK;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
+	rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
+	rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
+	val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+	val32 &= ~BIT(10);
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
+	val32 &= ~BIT(10);
+	rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
+
+	if (priv->tx_paths > 1) {
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+		rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000);
+	}
+
+	/* MAC settings */
+	rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
+
+	/* Page B init */
+	rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000);
+
+	if (priv->tx_paths > 1)
+		rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000);
+
+	/* IQ calibration setting */
+	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+	rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+	rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
+	for (i = 0; i < retry; i++) {
+		path_a_ok = rtl8xxxu_iqk_path_a(priv);
+		if (path_a_ok == 0x03) {
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_BEFORE_IQK_A);
+			result[t][0] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_AFTER_IQK_A);
+			result[t][1] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_RX_POWER_BEFORE_IQK_A_2);
+			result[t][2] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_RX_POWER_AFTER_IQK_A_2);
+			result[t][3] = (val32 >> 16) & 0x3ff;
+			break;
+		} else if (i == (retry - 1) && path_a_ok == 0x01) {
+			/* TX IQK OK */
+			dev_dbg(dev, "%s: Path A IQK Only Tx Success!!\n",
+				__func__);
+
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_BEFORE_IQK_A);
+			result[t][0] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_AFTER_IQK_A);
+			result[t][1] = (val32 >> 16) & 0x3ff;
+		}
+	}
+
+	if (!path_a_ok)
+		dev_dbg(dev, "%s: Path A IQK failed!\n", __func__);
+
+	if (priv->tx_paths > 1) {
+		/*
+		 * Path A into standby
+		 */
+		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x0);
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+		/* Turn Path B ADDA on */
+		rtl8xxxu_path_adda_on(priv, adda_regs, false);
+
+		for (i = 0; i < retry; i++) {
+			path_b_ok = rtl8xxxu_iqk_path_b(priv);
+			if (path_b_ok == 0x03) {
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+				result[t][4] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+				result[t][5] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+				result[t][6] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+				result[t][7] = (val32 >> 16) & 0x3ff;
+				break;
+			} else if (i == (retry - 1) && path_b_ok == 0x01) {
+				/* TX IQK OK */
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+				result[t][4] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+				result[t][5] = (val32 >> 16) & 0x3ff;
+			}
+		}
+
+		if (!path_b_ok)
+			dev_dbg(dev, "%s: Path B IQK failed!\n", __func__);
+	}
+
+	/* Back to BB mode, load original value */
+	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0);
+
+	if (t) {
+		if (!priv->pi_enabled) {
+			/*
+			 * Switch back BB to SI mode after finishing
+			 * IQ Calibration
+			 */
+			val32 = 0x01000000;
+			rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, val32);
+			rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, val32);
+		}
+
+		/* Reload ADDA power saving parameters */
+		rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup,
+				      RTL8XXXU_ADDA_REGS);
+
+		/* Reload MAC parameters */
+		rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+
+		/* Reload BB parameters */
+		rtl8xxxu_restore_regs(priv, iqk_bb_regs,
+				      priv->bb_backup, RTL8XXXU_BB_REGS);
+
+		/* Restore RX initial gain */
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3);
+
+		if (priv->tx_paths > 1) {
+			rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM,
+					 0x00032ed3);
+		}
+
+		/* Load 0xe30 IQC default value */
+		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00);
+		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00);
+	}
+}
+
+static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int result[4][8];	/* last is final result */
+	int i, candidate;
+	bool path_a_ok, path_b_ok;
+	u32 reg_e94, reg_e9c, reg_ea4, reg_eac;
+	u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	s32 reg_tmp = 0;
+	bool simu;
+
+	memset(result, 0, sizeof(result));
+	candidate = -1;
+
+	path_a_ok = false;
+	path_b_ok = false;
+
+	rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+
+	for (i = 0; i < 3; i++) {
+		rtl8xxxu_phy_iqcalibrate(priv, result, i);
+
+		if (i == 1) {
+			simu = rtl8xxxu_simularity_compare(priv, result, 0, 1);
+			if (simu) {
+				candidate = 0;
+				break;
+			}
+		}
+
+		if (i == 2) {
+			simu = rtl8xxxu_simularity_compare(priv, result, 0, 2);
+			if (simu) {
+				candidate = 0;
+				break;
+			}
+
+			simu = rtl8xxxu_simularity_compare(priv, result, 1, 2);
+			if (simu) {
+				candidate = 1;
+			} else {
+				for (i = 0; i < 8; i++)
+					reg_tmp += result[3][i];
+
+				if (reg_tmp)
+					candidate = 3;
+				else
+					candidate = -1;
+			}
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		reg_e94 = result[i][0];
+		reg_e9c = result[i][1];
+		reg_ea4 = result[i][2];
+		reg_eac = result[i][3];
+		reg_eb4 = result[i][4];
+		reg_ebc = result[i][5];
+		reg_ec4 = result[i][6];
+		reg_ecc = result[i][7];
+	}
+
+	if (candidate >= 0) {
+		reg_e94 = result[candidate][0];
+		priv->rege94 =  reg_e94;
+		reg_e9c = result[candidate][1];
+		priv->rege9c = reg_e9c;
+		reg_ea4 = result[candidate][2];
+		reg_eac = result[candidate][3];
+		reg_eb4 = result[candidate][4];
+		priv->regeb4 = reg_eb4;
+		reg_ebc = result[candidate][5];
+		priv->regebc = reg_ebc;
+		reg_ec4 = result[candidate][6];
+		reg_ecc = result[candidate][7];
+		dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate);
+		dev_dbg(dev,
+			"%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x "
+			"ecc=%x\n ", __func__, reg_e94, reg_e9c,
+			reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc);
+		path_a_ok = true;
+		path_b_ok = true;
+	} else {
+		reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100;
+		reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0;
+	}
+
+	if (reg_e94 && candidate >= 0)
+		rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result,
+					   candidate, (reg_ea4 == 0));
+
+	if (priv->tx_paths > 1 && reg_eb4)
+		rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
+					   candidate, (reg_ec4 == 0));
+
+	rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+			   priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
+}
+
+static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
+{
+	u32 val32;
+	u32 rf_amode, rf_bmode = 0, lstf;
+
+	/* Check continuous TX and Packet TX */
+	lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
+
+	if (lstf & OFDM_LSTF_MASK) {
+		/* Disable all continuous TX */
+		val32 = lstf & ~OFDM_LSTF_MASK;
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
+
+		/* Read original RF mode Path A */
+		rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC);
+
+		/* Set RF mode to standby Path A */
+		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC,
+				     (rf_amode & 0x8ffff) | 0x10000);
+
+		/* Path-B */
+		if (priv->tx_paths > 1) {
+			rf_bmode = rtl8xxxu_read_rfreg(priv, RF_B,
+						       RF6052_REG_AC);
+
+			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
+					     (rf_bmode & 0x8ffff) | 0x10000);
+		}
+	} else {
+		/*  Deal with Packet TX case */
+		/*  block all queues */
+		rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+	}
+
+	/* Start LC calibration */
+	val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG);
+	val32 |= 0x08000;
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32);
+
+	msleep(100);
+
+	/* Restore original parameters */
+	if (lstf & OFDM_LSTF_MASK) {
+		/* Path-A */
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, lstf);
+		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, rf_amode);
+
+		/* Path-B */
+		if (priv->tx_paths > 1)
+			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
+					     rf_bmode);
+	} else /*  Deal with Packet TX case */
+		rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
+}
+
+static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv)
+{
+	int i;
+	u16 reg;
+
+	reg = REG_MACID;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]);
+
+	return 0;
+}
+
+static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid)
+{
+	int i;
+	u16 reg;
+
+	dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid);
+
+	reg = REG_BSSID;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl8xxxu_write8(priv, reg + i, bssid[i]);
+
+	return 0;
+}
+
+static void
+rtl8xxxu_set_ampdu_factor(struct rtl8xxxu_priv *priv, u8 ampdu_factor)
+{
+	u8 vals[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+	u8 max_agg = 0xf;
+	int i;
+
+	ampdu_factor = 1 << (ampdu_factor + 2);
+	if (ampdu_factor > max_agg)
+		ampdu_factor = max_agg;
+
+	for (i = 0; i < 4; i++) {
+		if ((vals[i] & 0xf0) > (ampdu_factor << 4))
+			vals[i] = (vals[i] & 0x0f) | (ampdu_factor << 4);
+
+		if ((vals[i] & 0x0f) > ampdu_factor)
+			vals[i] = (vals[i] & 0xf0) | ampdu_factor;
+
+		rtl8xxxu_write8(priv, REG_AGGLEN_LMT + i, vals[i]);
+	}
+}
+
+static void rtl8xxxu_set_ampdu_min_space(struct rtl8xxxu_priv *priv, u8 density)
+{
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_AMPDU_MIN_SPACE);
+	val8 &= 0xf8;
+	val8 |= density;
+	rtl8xxxu_write8(priv, REG_AMPDU_MIN_SPACE, val8);
+}
+
+static int rtl8xxxu_active_to_emu(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	int count, ret;
+
+	/* Start of rtl8723AU_card_enable_flow */
+	/* Act to Cardemu sequence*/
+	/* Turn off RF */
+	rtl8xxxu_write8(priv, REG_RF_CTRL, 0);
+
+	/* 0x004E[7] = 0, switch DPDT_SEL_P output from register 0x0065[2] */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 &= ~LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+	/* 0x0005[1] = 1 turn off MAC by HW state machine*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 |= BIT(1);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+		if ((val8 & BIT(1)) == 0)
+			break;
+		udelay(10);
+	}
+
+	if (!count) {
+		dev_warn(&priv->udev->dev, "%s: Disabling MAC timed out\n",
+			 __func__);
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* 0x0000[5] = 1 analog Ips to digital, 1:isolation */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+	val8 |= SYS_ISO_ANALOG_IPS;
+	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+
+	/* 0x0020[0] = 0 disable LDOA12 MACRO block*/
+	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
+	val8 &= ~LDOA15_ENABLE;
+	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u8 val32;
+	int count, ret;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	/*
+	 * Poll - wait for RX packet to complete
+	 */
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, 0x5f8);
+		if (!val32)
+			break;
+		udelay(10);
+	}
+
+	if (!count) {
+		dev_warn(&priv->udev->dev,
+			 "%s: RX poll timed out (0x05f8)\n", __func__);
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* Disable CCK and OFDM, clock gated */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 &= ~SYS_FUNC_BBRSTB;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	udelay(2);
+
+	/* Reset baseband */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 &= ~SYS_FUNC_BB_GLB_RSTN;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	/* Reset MAC TRX */
+	val8 = rtl8xxxu_read8(priv, REG_CR);
+	val8 = CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE;
+	rtl8xxxu_write8(priv, REG_CR, val8);
+
+	/* Reset MAC TRX */
+	val8 = rtl8xxxu_read8(priv, REG_CR + 1);
+	val8 &= ~BIT(1); /* CR_SECURITY_ENABLE */
+	rtl8xxxu_write8(priv, REG_CR + 1, val8);
+
+	/* Respond TX OK to scheduler */
+	val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST);
+	val8 |= DUAL_TSF_TX_OK;
+	rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8);
+
+exit:
+	return ret;
+}
+
+static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	/* Clear suspend enable and power down enable*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(7));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* 0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/
+	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
+
+	/* 0x04[12:11] = 11 enable WL suspend*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(4));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+}
+
+static int rtl8xxxu_emu_to_active(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u32 val32;
+	int count, ret = 0;
+
+	/* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/
+	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
+	val8 |= LDOA15_ENABLE;
+	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
+
+	/* 0x67[0] = 0 to disable BT_GPS_SEL pins*/
+	val8 = rtl8xxxu_read8(priv, 0x0067);
+	val8 &= ~BIT(4);
+	rtl8xxxu_write8(priv, 0x0067, val8);
+
+	mdelay(1);
+
+	/* 0x00[5] = 0 release analog Ips to digital, 1:isolation */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+	val8 &= ~SYS_ISO_ANALOG_IPS;
+	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+
+	/* disable SW LPS 0x04[10]= 0 */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(2);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* wait till 0x04[17] = 1 power ready*/
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+		if (val32 & BIT(17))
+			break;
+
+		udelay(10);
+	}
+
+	if (!count) {
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* We should be able to optimize the following three entries into one */
+
+	/* release WLON reset 0x04[16]= 1*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
+
+	/* disable HWPDN 0x04[15]= 0*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(7);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* disable WL suspend*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(4));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* set, then poll until 0 */
+	val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+	val32 |= APS_FSMCO_MAC_ENABLE;
+	rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
+
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+		if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
+			ret = 0;
+			break;
+		}
+		udelay(10);
+	}
+
+	if (!count) {
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */
+	/*
+	 * Note: Vendor driver actually clears this bit, despite the
+	 * documentation claims it's being set!
+	 */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 |= LEDCFG2_DPDT_SELECT;
+	val8 &= ~LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	/* 0x0007[7:0] = 0x20 SOP option to disable BG/MB */
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x20);
+
+	/* 0x04[12:11] = 01 enable WL suspend */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(4);
+	val8 |= BIT(3);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 |= BIT(7);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* 0x48[16] = 1 to enable GPIO9 as EXT wakeup */
+	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
+
+	return 0;
+}
+
+static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int ret;
+
+	/*
+	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
+	 */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
+
+	rtl8xxxu_disabled_to_emu(priv);
+
+	ret = rtl8xxxu_emu_to_active(priv);
+	if (ret)
+		goto exit;
+
+	/*
+	 * 0x0004[19] = 1, reset 8051
+	 */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
+	val8 |= BIT(3);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
+
+	/*
+	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
+	 * Set CR bit10 to enable 32k calibration.
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
+		  CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
+		  CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
+		  CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE |
+		  CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	/* For EFuse PG */
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+	val32 &= ~(BIT(28) | BIT(29) | BIT(30));
+	val32 |= (0x06 << 28);
+	rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32);
+exit:
+	return ret;
+}
+
+static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int i;
+
+	for (i = 100; i; i--) {
+		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO);
+		if (val8 & APS_FSMCO_PFM_ALDN)
+			break;
+	}
+
+	if (!i) {
+		pr_info("%s: Poll failed\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
+	 */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, 0x2b);
+	udelay(100);
+
+	val8 = rtl8xxxu_read8(priv, REG_LDOV12D_CTRL);
+	if (!(val8 & LDOV12D_ENABLE)) {
+		pr_info("%s: Enabling LDOV12D (%02x)\n", __func__, val8);
+		val8 |= LDOV12D_ENABLE;
+		rtl8xxxu_write8(priv, REG_LDOV12D_CTRL, val8);
+
+		udelay(100);
+
+		val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+		val8 &= ~SYS_ISO_MD2PP;
+		rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+	}
+
+	/*
+	 * Auto enable WLAN
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
+	val16 |= APS_FSMCO_MAC_ENABLE;
+	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
+
+	for (i = 1000; i; i--) {
+		val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
+		if (!(val16 & APS_FSMCO_MAC_ENABLE))
+			break;
+	}
+	if (!i) {
+		pr_info("%s: FSMCO_MAC_ENABLE poll failed\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Enable radio, GPIO, LED
+	 */
+	val16 = APS_FSMCO_HW_SUSPEND | APS_FSMCO_ENABLE_POWERDOWN |
+		APS_FSMCO_PFM_ALDN;
+	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
+
+	/*
+	 * Release RF digital isolation
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
+	val16 &= ~SYS_ISO_DIOR;
+	rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
+
+	val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
+	val8 &= ~APSD_CTRL_OFF;
+	rtl8xxxu_write8(priv, REG_APSD_CTRL, val8);
+	for (i = 200; i; i--) {
+		val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
+		if (!(val8 & APSD_CTRL_OFF_STATUS))
+			break;
+	}
+
+	if (!i) {
+		pr_info("%s: APSD_CTRL poll failed\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
+		CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | CR_PROTOCOL_ENABLE |
+		CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE;
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	/*
+	 * Workaround for 8188RU LNA power leakage problem.
+	 */
+	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
+		val32 &= ~BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
+	}
+	return 0;
+}
+
+static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+	/*
+	 * Workaround for 8188RU LNA power leakage problem.
+	 */
+	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
+		val32 |= BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
+	}
+
+	rtl8xxxu_active_to_lps(priv);
+
+	/* Turn off RF */
+	rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00);
+
+	/* Reset Firmware if running in RAM */
+	if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL)
+		rtl8xxxu_firmware_self_reset(priv);
+
+	/* Reset MCU */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	val16 &= ~SYS_FUNC_CPU_ENABLE;
+	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+
+	/* Reset MCU ready status */
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
+
+	rtl8xxxu_active_to_emu(priv);
+	rtl8xxxu_emu_to_disabled(priv);
+
+	/* Reset MCU IO Wrapper */
+	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+
+	/* RSV_CTRL 0x1C[7:0] = 0x0e  lock ISO/CLK/Power control register */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e);
+}
+
+static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	struct rtl8xxxu_rfregval *rftable;
+	bool macpower;
+	int ret;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+	/* Check if MAC is already powered on */
+	val8 = rtl8xxxu_read8(priv, REG_CR);
+
+	/*
+	 * Fix 92DU-VC S3 hang with the reason is that secondary mac is not
+	 * initialized. First MAC returns 0xea, second MAC returns 0x00
+	 */
+	if (val8 == 0xea)
+		macpower = false;
+	else
+		macpower = true;
+
+	ret = priv->fops->power_on(priv);
+	if (ret < 0) {
+		dev_warn(dev, "%s: Failed power on\n", __func__);
+		goto exit;
+	}
+
+	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+	if (!macpower) {
+		ret = rtl8xxxu_init_llt_table(priv, TX_TOTAL_PAGE_NUM);
+		if (ret) {
+			dev_warn(dev, "%s: LLT table init failed\n", __func__);
+			goto exit;
+		}
+	}
+
+	ret = rtl8xxxu_download_firmware(priv);
+	dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+	ret = rtl8xxxu_start_firmware(priv);
+	dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table);
+	dev_dbg(dev, "%s: init_mac %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_init_phy_bb(priv);
+	dev_dbg(dev, "%s: init_phy_bb %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	switch(priv->rtlchip) {
+	case 0x8723a:
+		rftable = rtl8723au_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8188c:
+		if (priv->hi_pa)
+			rftable = rtl8188ru_radioa_1t_highpa_table;
+		else
+			rftable = rtl8192cu_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8191c:
+		rftable = rtl8192cu_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8192c:
+		rftable = rtl8192cu_radioa_2t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		if (ret)
+			break;
+		rftable = rtl8192cu_radiob_2t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		goto exit;
+
+	/* Reduce 80M spur */
+	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+
+	/* RFSW Control - clear bit 14 ?? */
+	rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003);
+	/* 0x07000760 */
+	val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW |
+		FPGA0_RF_ANTSWB | FPGA0_RF_PAPE |
+		((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE) <<
+		 FPGA0_RF_BD_CTRL_SHIFT);
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+	/* 0x860[6:5]= 00 - why? - this sets antenna B */
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66F60210);
+
+	priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A,
+						  RF6052_REG_MODE_AG);
+
+	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+	if (!macpower) {
+		if (priv->ep_tx_normal_queue)
+			val8 = TX_PAGE_NUM_NORM_PQ;
+		else
+			val8 = 0;
+
+		rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8);
+
+		val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD;
+
+		if (priv->ep_tx_high_queue)
+			val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT);
+		if (priv->ep_tx_low_queue)
+			val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT);
+
+		rtl8xxxu_write32(priv, REG_RQPN, val32);
+
+		/*
+		 * Set TX buffer boundary
+		 */
+		val8 = TX_TOTAL_PAGE_NUM + 1;
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8);
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8);
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8);
+		rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8);
+		rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8);
+	}
+
+	ret = rtl8xxxu_init_queue_priority(priv);
+	dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	/*
+	 * Set RX page boundary
+	 */
+	rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff);
+	/*
+	 * Transfer page size is always 128
+	 */
+	val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) |
+		(PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT);
+	rtl8xxxu_write8(priv, REG_PBP, val8);
+
+	/*
+	 * Unit in 8 bytes, not obvious what it is used for
+	 */
+	rtl8xxxu_write8(priv, REG_RX_DRVINFO_SZ, 4);
+
+	/*
+	 * Enable all interrupts - not obvious USB needs to do this
+	 */
+	rtl8xxxu_write32(priv, REG_HISR, 0xffffffff);
+	rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
+
+	rtl8xxxu_set_mac(priv);
+	rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION);
+
+	/*
+	 * Configure initial WMAC settings
+	 */
+	val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST |
+		/* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */
+		RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL |
+		RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC;
+	rtl8xxxu_write32(priv, REG_RCR, val32);
+
+	/*
+	 * Accept all multicast
+	 */
+	rtl8xxxu_write32(priv, REG_MAR, 0xffffffff);
+	rtl8xxxu_write32(priv, REG_MAR + 4, 0xffffffff);
+
+	/*
+	 * Init adaptive controls
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
+	val32 |= RESPONSE_RATE_RRSR_CCK_ONLY_1M;
+	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+	/* CCK = 0x0a, OFDM = 0x10 */
+#if 0
+	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
+#else
+	rtl8xxxu_set_spec_sifs(priv, 0x10, 0x10);
+#endif
+	rtl8xxxu_set_retry(priv, 0x30, 0x30);
+	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
+
+	/*
+	 * Init EDCA
+	 */
+	rtl8xxxu_write16(priv, REG_MAC_SPEC_SIFS, 0x100a);
+
+	/* Set CCK SIFS */
+	rtl8xxxu_write16(priv, REG_SIFS_CCK, 0x100a);
+
+	/* Set OFDM SIFS */
+	rtl8xxxu_write16(priv, REG_SIFS_OFDM, 0x100a);
+
+	/* TXOP */
+	rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, 0x005ea42b);
+	rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, 0x0000a44f);
+	rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, 0x005ea324);
+	rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, 0x002fa226);
+
+	/* Set data auto rate fallback retry count */
+	rtl8xxxu_write32(priv, REG_DARFRC, 0x00000000);
+	rtl8xxxu_write32(priv, REG_DARFRC + 4, 0x10080404);
+	rtl8xxxu_write32(priv, REG_RARFRC, 0x04030201);
+	rtl8xxxu_write32(priv, REG_RARFRC + 4, 0x08070605);
+
+	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL);
+	val8 |= FWHW_TXQ_CTRL_AMPDU_RETRY;
+	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, val8);
+
+	/*  Set ACK timeout */
+	rtl8xxxu_write8(priv, REG_ACKTO, 0x40);
+
+	/*
+	 * Initialize beacon parameters
+	 */
+	val16 = BEACON_DISABLE_TSF_UPDATE | (BEACON_DISABLE_TSF_UPDATE << 8);
+	rtl8xxxu_write16(priv, REG_BEACON_CTRL, val16);
+	rtl8xxxu_write16(priv, REG_TBTT_PROHIBIT, 0x6404);
+	rtl8xxxu_write8(priv, REG_DRIVER_EARLY_INT, DRIVER_EARLY_INT_TIME);
+	rtl8xxxu_write8(priv, REG_BEACON_DMA_TIME, BEACON_DMA_ATIME_INT_TIME);
+	rtl8xxxu_write16(priv, REG_BEACON_TCFG, 0x660F);
+
+	/*
+	 * Enable CCK and OFDM block
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 |= (FPGA_RF_MODE_CCK | FPGA_RF_MODE_OFDM);
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	/*
+	 * Invalidate all CAM entries - bit 30 is undocumented
+	 */
+	rtl8xxxu_write32(priv, REG_CAM_CMD, CAM_CMD_POLLING | BIT(30));
+
+	/*
+	 * Start out with default power levels for channel 6, 20MHz
+	 */
+	rtl8723a_set_tx_power(priv, 1, false);
+
+	/* Let the 8051 take control of antenna setting */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 |= LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+	rtl8xxxu_write8(priv, REG_HWSEQ_CTRL, 0xff);
+
+	/* Disable BAR - not sure if this has any effect on USB */
+	rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+	rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0);
+
+#if 0
+	/*
+	 * From 8192cu driver
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+	val32 &= ~BIT(6);
+	val32 |= BIT(5);
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+#endif
+
+	/*
+	 * Not sure if we should get into this at all
+	 */
+	if (priv->iqk_initialized) {
+		rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+				      priv->bb_recovery_backup,
+				      RTL8XXXU_BB_REGS);
+	} else {
+		rtl8723a_phy_iq_calibrate(priv);
+		priv->iqk_initialized = true;
+	}
+
+	/*
+	 * This should enable thermal meter
+	 */
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60);
+
+	rtl8723a_phy_lc_calibrate(priv);
+
+	/* fix USB interface interference issue */
+	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+	rtl8xxxu_write8(priv, 0xfe41, 0x8d);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+	rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320);
+
+	/* Solve too many protocol error on USB bus */
+	/* Can't do this for 8188/8192 UMC A cut parts */
+	rtl8xxxu_write8(priv, 0xfe40, 0xe6);
+	rtl8xxxu_write8(priv, 0xfe41, 0x94);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+	rtl8xxxu_write8(priv, 0xfe41, 0x19);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe5);
+	rtl8xxxu_write8(priv, 0xfe41, 0x91);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe2);
+	rtl8xxxu_write8(priv, 0xfe41, 0x81);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+#if 0
+	/* Init BT hw config. */
+	rtl8723a_init_bt(priv);
+#endif
+
+	/*
+	 * Not sure if we really need to save these parameters, but the
+	 * vendor driver does
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+	if (val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)
+		priv->path_a_hi_power = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	priv->path_a_rf_paths = val32 & OFDM_RF_PATH_RX_MASK;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1);
+	priv->path_a_ig_value = val32 & OFDM0_X_AGC_CORE1_IGI_MASK;
+
+	/* Set NAV_UPPER to 30000us */
+	val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT);
+	rtl8xxxu_write8(priv, REG_NAV_UPPER, val8);
+
+	/*
+	 * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test,
+	 * but we need to fin root cause.
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	if ((val32 & 0xff000000) != 0x83000000) {
+		val32 |= FPGA_RF_MODE_CCK;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL);
+	val32 |= FWHW_TXQ_CTRL_XMIT_MGMT_ACK;
+	/* ack for xmit mgmt frames. */
+	rtl8xxxu_write32(priv, REG_FWHW_TXQ_CTRL, val32);
+
+exit:
+	return ret;
+}
+
+static void rtl8xxxu_disable_device(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	rtl8xxxu_power_off(priv);
+}
+
+static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv,
+			       struct ieee80211_key_conf *key, const u8 *mac)
+{
+	u32 cmd, val32, addr, ctrl;
+	int j, i, tmp_debug;
+
+	tmp_debug = rtl8xxxu_debug;
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_KEY)
+		rtl8xxxu_debug |= RTL8XXXU_DEBUG_REG_WRITE;
+
+	addr = key->keyidx << CAM_CMD_KEY_SHIFT;
+	ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID;
+
+	for (j = 5; j >= 0; j--) {
+		switch (j) {
+		case 0:
+			val32 = ctrl | (mac[0] << 16) | (mac[1] << 24);
+			break;
+		case 1:
+			val32 = mac[2] | (mac[3] << 8) |
+				(mac[4] << 16) | (mac[5] << 24);
+			break;
+		default:
+			i = (j - 2) << 2;
+			val32 = key->key[i] | (key->key[i + 1] << 8) |
+				key->key[i + 2] << 16 | key->key[i + 3] << 24;
+			break;
+		}
+
+		rtl8xxxu_write32(priv, REG_CAM_WRITE, val32);
+		cmd = CAM_CMD_POLLING | CAM_CMD_WRITE | (addr + j);
+		rtl8xxxu_write32(priv, REG_CAM_CMD, cmd);
+		udelay(100);
+	}
+
+	rtl8xxxu_debug = tmp_debug;
+}
+
+static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif, const u8 *mac)
+{
+}
+
+static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+	val8 &= ~BEACON_DISABLE_TSF_UPDATE;
+	rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+}
+
+static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv,
+				      struct ieee80211_sta *sta)
+{
+	struct h2c_cmd h2c;
+	u32 ramask;
+
+	/* TODO: Set bits 28-31 for rate adaptive id */
+	ramask = (sta->supp_rates[0] & 0xfff) |
+		sta->ht_cap.mcs.rx_mask[0] << 12 |
+		sta->ht_cap.mcs.rx_mask[1] << 20;
+
+	h2c.ramask.cmd = H2C_SET_RATE_MASK;
+	h2c.ramask.mask_lo = cpu_to_le16(ramask & 0xffff);
+	h2c.ramask.mask_hi = cpu_to_le16(ramask >> 16);
+
+	h2c.ramask.arg = 0x80;
+	if (sta->ht_cap.cap &
+	    (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))
+		h2c.ramask.arg |= 0x20;
+
+	dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x\n", __func__,
+		ramask, h2c.ramask.arg);
+	rtl8723a_h2c_cmd(priv, &h2c);
+}
+
+static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
+{
+	u32 val32;
+	u8 rate_idx = 0;
+
+	rate_cfg &= RESPONSE_RATE_BITMAP_ALL;
+
+	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
+	val32 |= rate_cfg;
+	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+	dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__,	rate_cfg);
+
+	while (rate_cfg) {
+		rate_cfg = (rate_cfg >> 1);
+		rate_idx++;
+	}
+	rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx);
+}
+
+static void
+rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			  struct ieee80211_bss_conf *bss_conf, u32 changed)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	struct ieee80211_sta *sta;
+	struct rtl8xxxu_sta_priv *sta_priv;
+	u32 val32;
+#if 0
+	u16 val16;
+#endif
+	u8 val8;
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		struct h2c_cmd h2c;
+
+		dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc);
+
+		memset(&h2c, 0, sizeof(struct h2c_cmd));
+		rtl8xxxu_set_linktype(priv, vif->type);
+
+		if (bss_conf->assoc) {
+			rcu_read_lock();
+			sta = ieee80211_find_sta(vif, bss_conf->bssid);
+			if (!sta) {
+				dev_info(dev, "%s: ASSOC no sta found\n",
+					 __func__);
+				rcu_read_unlock();
+				goto error;
+			}
+
+			if (sta->ht_cap.ht_supported)
+				dev_info(dev, "%s: HT supported\n", __func__);
+			if (sta->vht_cap.vht_supported)
+				dev_info(dev, "%s: VHT supported\n", __func__);
+			rtl8xxxu_update_rate_mask(priv, sta);
+			rcu_read_unlock();
+
+			val32 = rtl8xxxu_read32(priv, REG_RCR);
+			val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON;
+			rtl8xxxu_write32(priv, REG_RCR, val32);
+
+			/* Enable RX of data frames */
+			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
+
+			rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
+
+			rtl8723a_stop_tx_beacon(priv);
+
+			/* joinbss sequence */
+			rtl8xxxu_write16(priv, REG_BCN_PSR_RPT,
+					 0xc000 | bss_conf->aid);
+
+#if 0
+			val16 = rtl8xxxu_read16(priv, REG_CR);
+			val16 |= CR_SW_BEACON_ENABLE;
+			rtl8xxxu_read16(priv, REG_CR, val16);
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 &= ~BEACON_FUNCTION_ENABLE;
+			val8 |= BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
+			if (val8 & BIT(6))
+				recover = true;
+
+			val8 &= ~BIT(6);
+			rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
+
+			/* build fake beacon */
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 |= BEACON_FUNCTION_ENABLE;
+			val8 &= ~BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			if (recover) {
+				val8 = rtl8xxxu_read8(priv,
+						      REG_FWHW_TXQ_CTRL + 2);
+				val8 |= BIT(6);
+				rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2,
+						val8);
+			}
+			val16 = rtl8xxxu_read16(priv, REG_CR);
+			val16 &= ~CR_SW_BEACON_ENABLE;
+			rtl8xxxu_read16(priv, REG_CR, val16);
+#endif
+			h2c.joinbss.data = H2C_JOIN_BSS_CONNECT;
+		} else {
+			val32 = rtl8xxxu_read32(priv, REG_RCR);
+			val32 &= ~(RCR_CHECK_BSSID_MATCH |
+				   RCR_CHECK_BSSID_BEACON);
+			rtl8xxxu_write32(priv, REG_RCR, val32);
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 |= BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			/* Disable RX of data frames */
+			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+			h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT;
+		}
+		h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT;
+		rtl8723a_h2c_cmd(priv, &h2c);
+	}
+
+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+		dev_dbg(dev, "Changed ERP_PREAMBLE: Use short preamble %i\n",
+			bss_conf->use_short_preamble);
+		val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+		if (bss_conf->use_short_preamble)
+			val32 |= RSR_ACK_SHORT_PREAMBLE;
+		else
+			val32 &= ~RSR_ACK_SHORT_PREAMBLE;
+		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+		rcu_read_lock();
+		sta = ieee80211_find_sta(vif, bss_conf->bssid);
+		if (sta) {
+			sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
+			if (bss_conf->use_short_preamble)
+				sta_priv->short_preamble = true;
+			else
+				sta_priv->short_preamble = false;
+		}
+		rcu_read_unlock();
+	}
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		dev_dbg(dev, "Changed ERP_SLOT: short_slot_time %i\n",
+			bss_conf->use_short_slot);
+
+		if (bss_conf->use_short_slot)
+			val8 = 9;
+		else
+			val8 = 20;
+		rtl8xxxu_write8(priv, REG_SLOT, val8);
+	}
+
+	if (changed & BSS_CHANGED_BSSID) {
+		dev_dbg(dev, "Changed BSSID!\n");
+		rtl8xxxu_set_bssid(priv, bss_conf->bssid);
+	}
+
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		dev_dbg(dev, "Changed BASIC_RATES!\n");
+		rtl8xxxu_set_basic_rates(priv, bss_conf->basic_rates);
+	}
+error:
+	return;
+}
+
+static u32 rtl8xxxu_80211_to_rtl_queue(u32 queue)
+{
+	u32 rtlqueue;
+
+	switch (queue) {
+	case IEEE80211_AC_VO:
+		rtlqueue = TXDESC_QUEUE_VO;
+		break;
+	case IEEE80211_AC_VI:
+		rtlqueue = TXDESC_QUEUE_VI;
+		break;
+	case IEEE80211_AC_BE:
+		rtlqueue = TXDESC_QUEUE_BE;
+		break;
+	case IEEE80211_AC_BK:
+		rtlqueue = TXDESC_QUEUE_BK;
+		break;
+	default:
+		rtlqueue = TXDESC_QUEUE_BE;
+	}
+
+	return rtlqueue;
+}
+
+static u32 rtl8xxxu_queue_select(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	u32 queue;
+
+	if (ieee80211_is_mgmt(hdr->frame_control))
+		queue = TXDESC_QUEUE_MGNT;
+	else
+		queue = rtl8xxxu_80211_to_rtl_queue(skb_get_queue_mapping(skb));
+
+	return queue;
+}
+
+static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc)
+{
+	__le16 *ptr = (__le16 *)tx_desc;
+	u16 csum = 0;
+	int i;
+
+	/*
+	 * Clear csum field before calculation, as the csum field is
+	 * in the middle of the struct.
+	 */
+	tx_desc->csum = cpu_to_le16(0);
+
+	for (i = 0; i < (sizeof(struct rtl8xxxu_tx_desc) / sizeof(u16)); i++)
+		csum = csum ^ le16_to_cpu(ptr[i]);
+
+	tx_desc->csum |= cpu_to_le16(csum);
+}
+
+static void rtl8xxxu_tx_complete(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_hw *hw;
+
+	tx_info = IEEE80211_SKB_CB(skb);
+	hw = tx_info->rate_driver_data[0];
+
+	skb_pull(skb, sizeof(struct rtl8xxxu_tx_desc));
+
+	ieee80211_tx_info_clear_status(tx_info);
+	tx_info->status.rates[0].idx = -1;
+	tx_info->status.rates[0].count = 0;
+
+#if 0
+	/*
+	 * Until we figure out how to obtain the info,
+	 * do not fool the stack.
+	 */
+	tx_info->flags |= IEEE80211_TX_STAT_ACK;
+#endif
+
+	ieee80211_tx_status_irqsafe(hw, skb);
+
+	usb_free_urb(urb);
+}
+
+static void rtl8xxxu_dump_action(struct device *dev,
+				 struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
+	u16 cap, timeout;
+
+	if (!(rtl8xxxu_debug & RTL8XXXU_DEBUG_ACTION))
+		return;
+
+	switch (mgmt->u.action.u.addba_resp.action_code) {
+	case WLAN_ACTION_ADDBA_RESP:
+		cap = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+		timeout = le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
+		dev_info(dev, "WLAN_ACTION_ADDBA_RESP: "
+			 "timeout %i, tid %02x, buf_size %02x, policy %02x, "
+			 "status %02x\n",
+			 timeout,
+			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
+			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
+			 (cap >> 1) & 0x1,
+			 le16_to_cpu(mgmt->u.action.u.addba_resp.status));
+		break;
+	case WLAN_ACTION_ADDBA_REQ:
+		cap = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+		timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+		dev_info(dev, "WLAN_ACTION_ADDBA_REQ: "
+			 "timeout %i, tid %02x, buf_size %02x, policy %02x\n",
+			 timeout,
+			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
+			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
+			 (cap >> 1) & 0x1);
+		break;
+	default:
+		dev_info(dev, "action frame %02x\n",
+			 mgmt->u.action.u.addba_resp.action_code);
+		break;
+	}
+}
+
+static void rtl8xxxu_tx(struct ieee80211_hw *hw,
+			struct ieee80211_tx_control *control,
+			struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct rtl8xxxu_tx_desc *tx_desc;
+	struct ieee80211_sta *sta = NULL;
+	struct rtl8xxxu_sta_priv *sta_priv = NULL;
+	struct device *dev = &priv->udev->dev;
+	struct urb *urb;
+	u32 queue, rate;
+	u16 pktlen = skb->len;
+	u16 seq_number;
+	u16 rate_flag = tx_info->control.rates[0].flags;
+	int ret;
+
+	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
+		dev_warn(dev,
+			 "%s: Not enough headroom (%i) for tx descriptor\n",
+			 __func__, skb_headroom(skb));
+		goto error;
+	}
+
+	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
+		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
+			 __func__, skb->len);
+		goto error;
+	}
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		dev_warn(dev, "%s: Unable to allocate urb\n", __func__);
+		goto error;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX)
+		dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n",
+			 __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen);
+
+	if (ieee80211_is_action(hdr->frame_control))
+		rtl8xxxu_dump_action(dev, hdr);
+
+	tx_info->rate_driver_data[0] = hw;
+
+	if (control && control->sta) {
+		sta = control->sta;
+		sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
+	}
+
+	tx_desc = (struct rtl8xxxu_tx_desc *)
+		skb_push(skb, sizeof(struct rtl8xxxu_tx_desc));
+
+	memset(tx_desc, 0, sizeof(struct rtl8xxxu_tx_desc));
+	tx_desc->pkt_size = cpu_to_le16(pktlen);
+	tx_desc->pkt_offset = sizeof(struct rtl8xxxu_tx_desc);
+
+	tx_desc->txdw0 =
+		TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT;
+	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+		tx_desc->txdw0 |= TXDESC_BROADMULTICAST;
+
+	queue = rtl8xxxu_queue_select(hw, skb);
+	tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT);
+
+	if (tx_info->control.hw_key) {
+		switch (tx_info->control.hw_key->cipher) {
+		case WLAN_CIPHER_SUITE_WEP40:
+		case WLAN_CIPHER_SUITE_WEP104:
+		case WLAN_CIPHER_SUITE_TKIP:
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_RC4);
+			break;
+		case WLAN_CIPHER_SUITE_CCMP:
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_AES);
+			break;
+		default:
+			break;
+		}
+	}
+
+	seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+	tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT);
+
+	if (rate_flag & IEEE80211_TX_RC_MCS)
+		rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0;
+	else
+		rate = tx_rate->hw_value;
+	tx_desc->txdw5 = cpu_to_le32(rate);
+
+	if (ieee80211_is_data(hdr->frame_control))
+		tx_desc->txdw5 |= cpu_to_le32(0x0001ff00);
+
+	/* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */
+	if (ieee80211_is_data_qos(hdr->frame_control) && sta) {
+		if (sta->ht_cap.ht_supported) {
+			u32 ampdu, val32;
+
+			ampdu = (u32)sta->ht_cap.ampdu_density;
+			val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;
+			tx_desc->txdw2 |= cpu_to_le32(val32);
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE);
+		} else
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
+	} else
+		tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
+
+	if (ieee80211_is_data_qos(hdr->frame_control))
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS);
+	if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ||
+	    (sta_priv && sta_priv->short_preamble))
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_SHORT_PREAMBLE);
+	if (rate_flag & IEEE80211_TX_RC_SHORT_GI ||
+	    (ieee80211_is_data_qos(hdr->frame_control) &&
+	     sta && sta->ht_cap.cap &
+	     (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) {
+		tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI);
+	}
+	if (ieee80211_is_mgmt(hdr->frame_control)) {
+		tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE);
+		tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT);
+		tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE);
+	}
+
+	if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
+		/* Use RTS rate 24M - does the mac80211 tell us which to use? */
+		tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE);
+	}
+
+	rtl8xxxu_calc_tx_desc_csum(tx_desc);
+
+	usb_fill_bulk_urb(urb, priv->udev, priv->pipe_out[queue], skb->data,
+			  skb->len, rtl8xxxu_tx_complete, skb);
+
+	usb_anchor_urb(urb, &priv->tx_anchor);
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		goto error;
+	}
+	return;
+error:
+	dev_kfree_skb(skb);
+}
+
+static void rtl8xxxu_rx_complete(struct urb *urb)
+{
+	struct rtl8xxxu_rx_urb *rx_urb =
+		container_of(urb, struct rtl8xxxu_rx_urb, urb);
+	struct ieee80211_hw *hw = rx_urb->hw;
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data;
+	struct rtl8723au_phy_stats *phy_stats;
+	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_mgmt *mgmt;
+	struct device *dev = &priv->udev->dev;
+	__le32 *_rx_desc_le = (__le32 *)skb->data;
+	u32 *_rx_desc = (u32 *)skb->data;
+	int cnt, len, drvinfo_sz, desc_shift, i, ret;
+
+	for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++)
+		_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
+
+	cnt = rx_desc->frag;
+	len = rx_desc->pktlen;
+	drvinfo_sz = rx_desc->drvinfo_sz * 8;
+	desc_shift = rx_desc->shift;
+	skb_put(skb, urb->actual_length);
+
+	if (urb->status == 0) {
+		skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc));
+		phy_stats = (struct rtl8723au_phy_stats *)skb->data;
+
+		skb_pull(skb, drvinfo_sz + desc_shift);
+
+		mgmt = (struct ieee80211_mgmt *)skb->data;
+
+		memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+		/*
+		 * Note this is valid for CCK rates only - FIXME
+		 */
+		if (rx_desc->phy_stats) {
+			u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
+
+			switch (cck_agc_rpt & 0xc0) {
+			case 0xc0:
+				rx_status->signal = -46 - (cck_agc_rpt & 0x3e);
+				break;
+			case 0x80:
+				rx_status->signal = -26 - (cck_agc_rpt & 0x3e);
+				break;
+			case 0x40:
+				rx_status->signal = -12 - (cck_agc_rpt & 0x3e);
+				break;
+			case 0x00:
+				rx_status->signal = 16 - (cck_agc_rpt & 0x3e);
+				break;
+			}
+		}
+
+		rx_status->freq = hw->conf.chandef.chan->center_freq;
+		rx_status->band = hw->conf.chandef.chan->band;
+
+		rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
+
+		if (!rx_desc->swdec)
+			rx_status->flag |= RX_FLAG_DECRYPTED;
+		if (rx_desc->crc32)
+			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+		if (rx_desc->bw)
+			rx_status->flag |= RX_FLAG_40MHZ;
+
+		if (rx_desc->rxht) {
+			rx_status->flag |= RX_FLAG_HT;
+			rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
+		} else {
+			rx_status->rate_idx = rx_desc->rxmcs;
+		}
+
+		ieee80211_rx_irqsafe(hw, skb);
+		skb = NULL;
+		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+		if (ret) {
+			dev_warn(dev, "%s: Unable to allocate skb\n", __func__);
+			goto cleanup;
+		}
+	} else {
+		dev_dbg(dev, "%s: status %i\n",	__func__, urb->status);
+		goto cleanup;
+	}
+	return;
+
+cleanup:
+	usb_free_urb(urb);
+	dev_kfree_skb(skb);
+	return;
+}
+
+static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb)
+{
+	struct sk_buff *skb;
+	int skb_size;
+	int ret;
+
+	skb_size = sizeof(struct rtl8xxxu_rx_desc) + RTL_RX_BUFFER_SIZE;
+	skb = dev_alloc_skb(skb_size);
+	if (!skb)
+		return -ENOMEM;
+
+	memset(skb->data, 0, sizeof(struct rtl8xxxu_rx_desc));
+	usb_fill_bulk_urb(&rx_urb->urb, priv->udev, priv->pipe_in, skb->data,
+			  skb_size, rtl8xxxu_rx_complete, skb);
+	usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor);
+	ret = usb_submit_urb(&rx_urb->urb, GFP_ATOMIC);
+	if (ret)
+		usb_unanchor_urb(&rx_urb->urb);
+	return ret;
+}
+
+static void rtl8xxxu_int_complete(struct urb *urb)
+{
+	struct rtl8xxxu_priv *priv = (struct rtl8xxxu_priv *)urb->context;
+	struct device *dev = &priv->udev->dev;
+	int ret;
+
+	dev_dbg(dev, "%s: status %i\n", __func__, urb->status);
+	if (urb->status == 0) {
+		usb_anchor_urb(urb, &priv->int_anchor);
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret)
+			usb_unanchor_urb(urb);
+	} else {
+		dev_info(dev, "%s: Error %i\n", __func__, urb->status);
+	}
+}
+
+
+static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct urb *urb;
+	u32 val32;
+	int ret;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	usb_fill_int_urb(urb, priv->udev, priv->pipe_interrupt,
+			 priv->int_buf, USB_INTR_CONTENT_LENGTH,
+			 rtl8xxxu_int_complete, priv, 1);
+	usb_anchor_urb(urb, &priv->int_anchor);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		goto error;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_USB_HIMR);
+	val32 |= USB_HIMR_CPWM;
+	rtl8xxxu_write32(priv, REG_USB_HIMR, val32);
+
+error:
+	return ret;
+}
+
+static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	int ret;
+	u8 val8;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		rtl8723a_stop_tx_beacon(priv);
+
+		val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+		val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE |
+			BEACON_DISABLE_TSF_UPDATE;
+		rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+		ret = 0;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	rtl8xxxu_set_linktype(priv, vif->type);
+
+	return ret;
+}
+
+static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	dev_dbg(&priv->udev->dev, "%s\n", __func__);
+}
+
+static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u16 val16;
+	int ret = 0, channel;
+	bool ht40;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
+		dev_info(dev,
+			 "%s: channel: %i (changed %08x chandef.width %02x)\n",
+			 __func__, hw->conf.chandef.chan->hw_value,
+			 changed, hw->conf.chandef.width);
+
+	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
+		val16 = ((hw->conf.long_frame_max_tx_count <<
+			  RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) |
+			((hw->conf.short_frame_max_tx_count <<
+			  RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK);
+		rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		switch (hw->conf.chandef.width) {
+		case NL80211_CHAN_WIDTH_20_NOHT:
+		case NL80211_CHAN_WIDTH_20:
+			ht40 = false;
+			break;
+		case NL80211_CHAN_WIDTH_40:
+			ht40 = true;
+			break;
+		default:
+			ret = -ENOTSUPP;
+			goto exit;
+		}
+
+		channel = hw->conf.chandef.chan->hw_value;
+
+		rtl8723a_set_tx_power(priv, channel, ht40);
+
+		rtl8723au_config_channel(hw);
+	}
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif, u16 queue,
+			    const struct ieee80211_tx_queue_params *param)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u32 val32;
+	u8 aifs, acm_ctrl, acm_bit;
+
+	aifs = param->aifs;
+
+	val32 = aifs |
+		fls(param->cw_min) << EDCA_PARAM_ECW_MIN_SHIFT |
+		fls(param->cw_max) << EDCA_PARAM_ECW_MAX_SHIFT |
+		(u32)param->txop << EDCA_PARAM_TXOP_SHIFT;
+
+	acm_ctrl = rtl8xxxu_read8(priv, REG_ACM_HW_CTRL);
+	dev_dbg(dev,
+		"%s: IEEE80211 queue %02x val %08x, acm %i, acm_ctrl %02x\n",
+		__func__, queue, val32, param->acm, acm_ctrl);
+
+	switch (queue) {
+	case IEEE80211_AC_VO:
+		acm_bit = ACM_HW_CTRL_VO;
+		rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, val32);
+		break;
+	case IEEE80211_AC_VI:
+		acm_bit = ACM_HW_CTRL_VI;
+		rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, val32);
+		break;
+	case IEEE80211_AC_BE:
+		acm_bit = ACM_HW_CTRL_BE;
+		rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, val32);
+		break;
+	case IEEE80211_AC_BK:
+		acm_bit = ACM_HW_CTRL_BK;
+		rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, val32);
+		break;
+	default:
+		acm_bit = 0;
+		break;
+	}
+
+	if (param->acm)
+		acm_ctrl |= acm_bit;
+	else
+		acm_ctrl &= ~acm_bit;
+	rtl8xxxu_write8(priv, REG_ACM_HW_CTRL, acm_ctrl);
+
+	return 0;
+}
+
+static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw,
+				      unsigned int changed_flags,
+				      unsigned int *total_flags, u64 multicast)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n",
+		__func__, changed_flags, *total_flags);
+
+	*total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC);
+}
+
+static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts)
+{
+	if (rts > 2347)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			    struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta,
+			    struct ieee80211_key_conf *key)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u8 mac_addr[ETH_ALEN];
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int retval = -EOPNOTSUPP;
+
+	dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n",
+		__func__, cmd, key->cipher, key->keyidx);
+
+	if (vif->type != NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
+
+	if (key->keyidx > 3)
+		return -EOPNOTSUPP;
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
+		dev_dbg(dev, "%s: pairwise key\n", __func__);
+		ether_addr_copy(mac_addr, sta->addr);
+	} else {
+		dev_dbg(dev, "%s: group key\n", __func__);
+		eth_broadcast_addr(mac_addr);
+	}
+
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= CR_SECURITY_ENABLE;
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	val8 = SEC_CFG_TX_SEC_ENABLE | SEC_CFG_TXBC_USE_DEFKEY |
+		SEC_CFG_RX_SEC_ENABLE | SEC_CFG_RXBC_USE_DEFKEY;
+	val8 |= SEC_CFG_TX_USE_DEFKEY | SEC_CFG_RX_USE_DEFKEY;
+	rtl8xxxu_write8(priv, REG_SECURITY_CFG, val8);
+
+	switch (cmd) {
+	case SET_KEY:
+		/*
+		 * This is a bit of a hack - the lower bits of the cipher
+		 * suite selector happens to match the cipher index in the
+		 * CAM
+		 */
+		key->hw_key_idx = key->keyidx;
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		rtl8xxxu_cam_write(priv, key, mac_addr);
+		retval = 0;
+		break;
+	case DISABLE_KEY:
+		rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000);
+		val32 = CAM_CMD_POLLING | CAM_CMD_WRITE |
+			key->keyidx << CAM_CMD_KEY_SHIFT;
+		rtl8xxxu_write32(priv, REG_CAM_CMD, val32);
+		retval = 0;
+		break;
+	default:
+		dev_warn(dev, "%s: Unsupported command %02x\n", __func__, cmd);
+	}
+
+	return retval;
+}
+
+static int
+rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		      enum ieee80211_ampdu_mlme_action action,
+		      struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u8 ampdu_factor, ampdu_density;
+
+	switch (action) {
+	case IEEE80211_AMPDU_TX_START:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_START\n", __func__);
+		ampdu_factor = sta->ht_cap.ampdu_factor;
+		ampdu_density = sta->ht_cap.ampdu_density;
+		rtl8xxxu_set_ampdu_factor(priv, ampdu_factor);
+		rtl8xxxu_set_ampdu_min_space(priv, ampdu_density);
+		dev_dbg(dev,
+			"Changed HT: ampdu_factor %02x, ampdu_density %02x\n",
+			ampdu_factor, ampdu_density);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);
+		rtl8xxxu_set_ampdu_factor(priv, 0);
+		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",
+			 __func__);
+		rtl8xxxu_set_ampdu_factor(priv, 0);
+		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		break;
+	case IEEE80211_AMPDU_RX_START:
+		dev_info(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		dev_info(dev, "%s: IEEE80211_AMPDU_RX_STOP\n", __func__);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int rtl8xxxu_sta_add(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta)
+{
+	struct rtl8xxxu_sta_priv *sta_priv;
+
+	sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
+
+	sta_priv->short_preamble = false;
+	return 0;
+};
+
+static int rtl8xxxu_sta_remove(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_sta *sta)
+{
+	return 0;
+};
+
+static int rtl8xxxu_start(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct rtl8xxxu_rx_urb *rx_urb;
+	int ret, i;
+
+	ret = 0;
+
+	init_usb_anchor(&priv->rx_anchor);
+	init_usb_anchor(&priv->tx_anchor);
+	init_usb_anchor(&priv->int_anchor);
+
+	rtl8723a_enable_rf(priv);
+	ret = rtl8xxxu_submit_int_urb(hw);
+	if (ret)
+		goto exit;
+
+	for (i = 0; i < 32; i++) {
+		rx_urb = kmalloc(sizeof(struct rtl8xxxu_rx_urb), GFP_ATOMIC);
+		if (!rx_urb) {
+			if (!i)
+				ret = -ENOMEM;
+
+			goto exit;
+		}
+		usb_init_urb(&rx_urb->urb);
+		rx_urb->hw = hw;
+
+		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+	}
+exit:
+	/*
+	 * Disable all data frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+	/*
+	 * Accept all mgmt frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff);
+
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e);
+
+	return ret;
+}
+
+static void rtl8xxxu_stop(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000);
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+
+	usb_kill_anchored_urbs(&priv->rx_anchor);
+	usb_kill_anchored_urbs(&priv->tx_anchor);
+	usb_kill_anchored_urbs(&priv->int_anchor);
+
+	rtl8723a_disable_rf(priv);
+
+	/*
+	 * Disable interrupts
+	 */
+	rtl8xxxu_write32(priv, REG_USB_HIMR, 0);
+}
+
+static const struct ieee80211_ops rtl8xxxu_ops = {
+	.tx = rtl8xxxu_tx,
+	.add_interface = rtl8xxxu_add_interface,
+	.remove_interface = rtl8xxxu_remove_interface,
+	.config = rtl8xxxu_config,
+	.conf_tx = rtl8xxxu_conf_tx,
+	.bss_info_changed = rtl8xxxu_bss_info_changed,
+	.configure_filter = rtl8xxxu_configure_filter,
+	.set_rts_threshold = rtl8xxxu_set_rts_threshold,
+	.start = rtl8xxxu_start,
+	.stop = rtl8xxxu_stop,
+	.sw_scan_start = rtl8xxxu_sw_scan_start,
+	.sw_scan_complete = rtl8xxxu_sw_scan_complete,
+	.set_key = rtl8xxxu_set_key,
+	.ampdu_action = rtl8xxxu_ampdu_action,
+	.sta_add = rtl8xxxu_sta_add,
+	.sta_remove = rtl8xxxu_sta_remove,
+};
+
+static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv,
+			      struct usb_interface *interface)
+{
+	struct usb_interface_descriptor *interface_desc;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct device *dev = &priv->udev->dev;
+	int i, j = 0, endpoints;
+	u8 dir, xtype, num;
+	int ret = 0;
+
+	host_interface = &interface->altsetting[0];
+	interface_desc = &host_interface->desc;
+	endpoints = interface_desc->bNumEndpoints;
+
+	for (i = 0; i < endpoints; i++) {
+		endpoint = &host_interface->endpoint[i].desc;
+
+		dir = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		num = usb_endpoint_num(endpoint);
+		xtype = usb_endpoint_type(endpoint);
+		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+			dev_dbg(dev,
+				"%s: endpoint: dir %02x, # %02x, type %02x\n",
+				__func__, dir, num, xtype);
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: in endpoint num %i\n",
+					__func__, num);
+
+			if (priv->pipe_in) {
+				dev_warn(dev,
+					 "%s: Too many IN pipes\n", __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			priv->pipe_in =	usb_rcvbulkpipe(priv->udev, num);
+		}
+
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_int(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: interrupt endpoint num %i\n",
+					__func__, num);
+
+			if (priv->pipe_interrupt) {
+				dev_warn(dev, "%s: Too many INTERRUPT pipes\n",
+					 __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			priv->pipe_interrupt = usb_rcvintpipe(priv->udev, num);
+		}
+
+		if (usb_endpoint_dir_out(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: out endpoint num %i\n",
+					__func__, num);
+			if (j >= RTL8XXXU_OUT_ENDPOINTS) {
+				dev_warn(dev,
+					 "%s: Too many OUT pipes\n", __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+			priv->out_ep[j++] = num;
+		}
+	}
+exit:
+	priv->nr_out_eps = j;
+	return ret;
+}
+
+static int rtl8xxxu_probe(struct usb_interface *interface,
+			  const struct usb_device_id *id)
+{
+	struct rtl8xxxu_priv *priv;
+	struct ieee80211_hw *hw;
+	struct usb_device *udev;
+	struct ieee80211_supported_band *sband;
+	int ret = 0;
+	int untested = 1;
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+
+	switch (id->idVendor) {
+	case USB_VENDOR_ID_REALTEK:
+		switch(id->idProduct) {
+		case 0x1724:
+		case 0x8176:
+		case 0x8178:
+		case 0x817f:
+			untested = 0;
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (untested) {
+		rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE;
+		dev_info(&udev->dev,
+			 "This Realtek USB WiFi dongle (0x%04x:0x%04x) is untested!\n",
+			 id->idVendor, id->idProduct);
+		dev_info(&udev->dev,
+			 "Please report results to Jes.Sorensen@gmail.com\n");
+	}
+
+	hw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), &rtl8xxxu_ops);
+	if (!hw) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	priv = hw->priv;
+	priv->hw = hw;
+	priv->udev = udev;
+	priv->fops = (struct rtl8xxxu_fileops *)id->driver_info;
+	mutex_init(&priv->usb_buf_mutex);
+	mutex_init(&priv->h2c_mutex);
+
+	usb_set_intfdata(interface, hw);
+
+	ret = rtl8xxxu_parse_usb(priv, interface);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_identify_chip(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to identify chip\n");
+		goto exit;
+	}
+
+	ret = rtl8xxxu_read_efuse(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to read EFuse\n");
+		goto exit;
+	}
+
+	ret = priv->fops->parse_efuse(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to parse EFuse\n");
+		goto exit;
+	}
+
+	rtl8xxxu_print_chipinfo(priv);
+
+	ret = priv->fops->load_firmware(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to load firmware\n");
+		goto exit;
+	}
+
+	ret = rtl8xxxu_init_device(hw);
+
+	hw->wiphy->max_scan_ssids = 1;
+	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	hw->queues = 4;
+
+	sband = &rtl8xxxu_supported_band;
+	sband->ht_cap.ht_supported = true;
+	sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+	sband->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+	sband->ht_cap.cap = /* IEEE80211_HT_CAP_SUP_WIDTH_20_40 | */
+		IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40;
+	memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs));
+	sband->ht_cap.mcs.rx_mask[0] = 0xff;
+	sband->ht_cap.mcs.rx_mask[4] = 0x01;
+	if (priv->rf_paths > 1) {
+		sband->ht_cap.mcs.rx_mask[1] = 0xff;
+		sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+	}
+	sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+	hw->wiphy->rts_threshold = 2347;
+
+	SET_IEEE80211_DEV(priv->hw, &interface->dev);
+	SET_IEEE80211_PERM_ADDR(hw, priv->mac_addr);
+
+	hw->extra_tx_headroom = sizeof(struct rtl8xxxu_tx_desc);
+	hw->sta_data_size = sizeof(struct rtl8xxxu_sta_priv);
+	ieee80211_hw_set(hw, SIGNAL_DBM);
+	/*
+	 * The firmware handles rate control
+	 */
+	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
+	ret = ieee80211_register_hw(priv->hw);
+	if (ret) {
+		dev_err(&udev->dev, "%s: Failed to register: %i\n",
+			__func__, ret);
+		goto exit;
+	}
+
+exit:
+	if (ret < 0)
+		usb_put_dev(udev);
+	return ret;
+}
+
+static void rtl8xxxu_disconnect(struct usb_interface *interface)
+{
+	struct rtl8xxxu_priv *priv;
+	struct ieee80211_hw *hw;
+
+	hw = usb_get_intfdata(interface);
+	priv = hw->priv;
+
+	rtl8xxxu_disable_device(hw);
+	usb_set_intfdata(interface, NULL);
+
+	dev_info(&priv->udev->dev, "disconnecting\n");
+
+	ieee80211_unregister_hw(hw);
+
+	kfree(priv->fw_data);
+	mutex_destroy(&priv->usb_buf_mutex);
+	mutex_destroy(&priv->h2c_mutex);
+
+	usb_put_dev(priv->udev);
+	ieee80211_free_hw(hw);
+}
+
+static struct rtl8xxxu_fileops rtl8723au_fops = {
+	.parse_efuse = rtl8723au_parse_efuse,
+	.load_firmware = rtl8723au_load_firmware,
+	.power_on = rtl8723au_power_on,
+	.writeN = rtl8xxxu_writeN,
+};
+
+static struct rtl8xxxu_fileops rtl8192cu_fops = {
+	.parse_efuse = rtl8192cu_parse_efuse,
+	.load_firmware = rtl8192cu_load_firmware,
+	.power_on = rtl8192cu_power_on,
+	.writeN = rtl8xxxu_slow_writeN,
+};
+
+static struct usb_device_id dev_table[] = {
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8178, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+#ifdef CONFIG_RTL8XXXU_UNTESTED
+/* Currently untested 8188 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8177, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x1058, 0x0631, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x094c, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1102, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ba, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1e1e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x5088, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0052, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x005c, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0eb0, 0x9071, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x103c, 0x1629, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x13d3, 0x3357, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x4902, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xed17, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x648b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0090, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4856, 0x0091, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7811, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffa, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff8, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffb, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffc, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x1201, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+/* Currently untested 8192 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0950, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2102, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2103, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x341f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe035, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ab, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0061, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0070, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0789, 0x016d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07aa, 0x0056, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8178, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9021, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0xf001, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x2e2e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0019, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0020, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3307, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3309, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x624d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0100, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0091, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+#endif
+{ }
+};
+
+static struct usb_driver rtl8xxxu_driver = {
+	.name = DRIVER_NAME,
+	.probe = rtl8xxxu_probe,
+	.disconnect = rtl8xxxu_disconnect,
+	.id_table = dev_table,
+	.disable_hub_initiated_lpm = 1,
+};
+
+static int __init rtl8xxxu_module_init(void)
+{
+	int res;
+
+	res = usb_register(&rtl8xxxu_driver);
+	if (res < 0)
+		pr_err(DRIVER_NAME ": usb_register() failed (%i)\n", res);
+
+	return res;
+}
+
+static void __exit rtl8xxxu_module_exit(void)
+{
+	usb_deregister(&rtl8xxxu_driver);
+}
+
+
+MODULE_DEVICE_TABLE(usb, dev_table);
+
+module_init(rtl8xxxu_module_init);
+module_exit(rtl8xxxu_module_exit);
diff --git a/drivers/net/wireless/rtl8xxxu.h b/drivers/net/wireless/rtl8xxxu.h
new file mode 100644
index 0000000..ad499f9
--- /dev/null
+++ b/drivers/net/wireless/rtl8xxxu.h
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Register definitions taken from original Realtek rtl8723au driver
+ */
+
+#include <asm/byteorder.h>
+
+#define RTL8XXXU_DEBUG_REG_WRITE	0x01
+#define RTL8XXXU_DEBUG_REG_READ		0x02
+#define RTL8XXXU_DEBUG_RFREG_WRITE	0x04
+#define RTL8XXXU_DEBUG_RFREG_READ	0x08
+#define RTL8XXXU_DEBUG_CHANNEL		0x10
+#define RTL8XXXU_DEBUG_TX		0x20
+#define RTL8XXXU_DEBUG_TX_DUMP		0x40
+#define RTL8XXXU_DEBUG_RX		0x80
+#define RTL8XXXU_DEBUG_RX_DUMP		0x100
+#define RTL8XXXU_DEBUG_USB		0x200
+#define RTL8XXXU_DEBUG_KEY		0x400
+#define RTL8XXXU_DEBUG_H2C		0x800
+#define RTL8XXXU_DEBUG_ACTION		0x1000
+#define RTL8XXXU_DEBUG_EFUSE		0x2000
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT	500
+#define RTL8XXXU_MAX_REG_POLL		500
+#define	USB_INTR_CONTENT_LENGTH		56
+
+#define RTL8XXXU_OUT_ENDPOINTS		3
+
+#define REALTEK_USB_READ		0xc0
+#define REALTEK_USB_WRITE		0x40
+#define REALTEK_USB_CMD_REQ		0x05
+#define REALTEK_USB_CMD_IDX		0x00
+
+#define TX_TOTAL_PAGE_NUM		0xf8
+/* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */
+#define TX_PAGE_NUM_PUBQ		0xe7
+#define TX_PAGE_NUM_HI_PQ		0x0c
+#define TX_PAGE_NUM_LO_PQ		0x02
+#define TX_PAGE_NUM_NORM_PQ		0x02
+
+#define RTL_FW_PAGE_SIZE		4096
+#define RTL8XXXU_FIRMWARE_POLL_MAX	1000
+
+#define RTL8723A_CHANNEL_GROUPS		3
+#define RTL8723A_MAX_RF_PATHS		2
+#define RF6052_MAX_TX_PWR		0x3f
+
+#define EFUSE_MAP_LEN_8723A		256
+#define EFUSE_MAX_SECTION_8723A		32
+#define EFUSE_REAL_CONTENT_LEN_8723A	512
+#define EFUSE_BT_MAP_LEN_8723A		1024
+#define EFUSE_MAX_WORD_UNIT		4
+
+struct rtl8xxxu_rx_desc {
+	u32 pktlen:14;
+	u32 crc32:1;
+	u32 icverr:1;
+	u32 drvinfo_sz:4;
+	u32 security:3;
+	u32 qos:1;
+	u32 shift:2;
+	u32 phy_stats:1;
+	u32 swdec:1;
+	u32 ls:1;
+	u32 fs:1;
+	u32 eor:1;
+	u32 own:1;
+
+	u32 macid:5;
+	u32 tid:4;
+	u32 hwrsvd:4;
+	u32 amsdu:1;
+	u32 paggr:1;
+	u32 faggr:1;
+	u32 a1fit:4;
+	u32 a2fit:4;
+	u32 pam:1;
+	u32 pwr:1;
+	u32 md:1;
+	u32 mf:1;
+	u32 type:2;
+	u32 mc:1;
+	u32 bc:1;
+
+	u32 seq:12;
+	u32 frag:4;
+	u32 nextpktlen:14;
+	u32 nextind:1;
+	u32 reserved0:1;
+
+	u32 rxmcs:6;
+	u32 rxht:1;
+	u32 gf:1;
+	u32 splcp:1;
+	u32 bw:1;
+	u32 htc:1;
+	u32 eosp:1;
+	u32 bssidfit:2;
+	u32 reserved1:16;
+	u32 unicastwake:1;
+	u32 magicwake:1;
+
+	u32 pattern0match:1;
+	u32 pattern1match:1;
+	u32 pattern2match:1;
+	u32 pattern3match:1;
+	u32 pattern4match:1;
+	u32 pattern5match:1;
+	u32 pattern6match:1;
+	u32 pattern7match:1;
+	u32 pattern8match:1;
+	u32 pattern9match:1;
+	u32 patternamatch:1;
+	u32 patternbmatch:1;
+	u32 patterncmatch:1;
+	u32 reserved2:19;
+
+	__le32 tsfl;
+#if 0
+	u32 bassn:12;
+	u32 bavld:1;
+	u32 reserved3:19;
+#endif
+};
+
+struct rtl8xxxu_tx_desc {
+	__le16 pkt_size;
+	u8 pkt_offset;
+	u8 txdw0;
+	__le32 txdw1;
+	__le32 txdw2;
+	__le32 txdw3;
+	__le32 txdw4;
+	__le32 txdw5;
+	__le32 txdw6;
+	__le16 csum;
+	__le16 txdw7;
+};
+
+/*  CCK Rates, TxHT = 0 */
+#define DESC_RATE_1M			0x00
+#define DESC_RATE_2M			0x01
+#define DESC_RATE_5_5M			0x02
+#define DESC_RATE_11M			0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC_RATE_6M			0x04
+#define DESC_RATE_9M			0x05
+#define DESC_RATE_12M			0x06
+#define DESC_RATE_18M			0x07
+#define DESC_RATE_24M			0x08
+#define DESC_RATE_36M			0x09
+#define DESC_RATE_48M			0x0a
+#define DESC_RATE_54M			0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC_RATE_MCS0			0x0c
+#define DESC_RATE_MCS1			0x0d
+#define DESC_RATE_MCS2			0x0e
+#define DESC_RATE_MCS3			0x0f
+#define DESC_RATE_MCS4			0x10
+#define DESC_RATE_MCS5			0x11
+#define DESC_RATE_MCS6			0x12
+#define DESC_RATE_MCS7			0x13
+#define DESC_RATE_MCS8			0x14
+#define DESC_RATE_MCS9			0x15
+#define DESC_RATE_MCS10			0x16
+#define DESC_RATE_MCS11			0x17
+#define DESC_RATE_MCS12			0x18
+#define DESC_RATE_MCS13			0x19
+#define DESC_RATE_MCS14			0x1a
+#define DESC_RATE_MCS15			0x1b
+#define DESC_RATE_MCS15_SG		0x1c
+#define DESC_RATE_MCS32			0x20
+
+#define TXDESC_OFFSET_SZ		0
+#define TXDESC_OFFSET_SHT		16
+#if 0
+#define TXDESC_BMC			BIT(24)
+#define TXDESC_LSG			BIT(26)
+#define TXDESC_FSG			BIT(27)
+#define TXDESC_OWN			BIT(31)
+#else
+#define TXDESC_BROADMULTICAST		BIT(0)
+#define TXDESC_LAST_SEGMENT		BIT(2)
+#define TXDESC_FIRST_SEGMENT		BIT(3)
+#define TXDESC_OWN			BIT(7)
+#endif
+
+/* Word 1 */
+#define TXDESC_PKT_OFFSET_SZ		0
+#define TXDESC_AGG_ENABLE		BIT(5)
+#define TXDESC_BK			BIT(6)
+#define TXDESC_QUEUE_SHIFT		8
+#define TXDESC_QUEUE_MASK		0x1f00
+#define TXDESC_QUEUE_BK			0x2
+#define TXDESC_QUEUE_BE			0x0
+#define TXDESC_QUEUE_VI			0x5
+#define TXDESC_QUEUE_VO			0x7
+#define TXDESC_QUEUE_BEACON		0x10
+#define TXDESC_QUEUE_HIGH		0x11
+#define TXDESC_QUEUE_MGNT		0x12
+#define TXDESC_QUEUE_CMD		0x13
+#define TXDESC_QUEUE_MAX		(TXDESC_QUEUE_CMD + 1)
+
+#define DESC_RATE_ID_SHIFT		16
+#define DESC_RATE_ID_MASK		0xf
+#define TXDESC_NAVUSEHDR		BIT(20)
+#define TXDESC_SEC_RC4			0x00400000
+#define TXDESC_SEC_AES			0x00c00000
+#define TXDESC_PKT_OFFSET_SHIFT		26
+#define TXDESC_AGG_EN			BIT(29)
+#define TXDESC_HWPC			BIT(31)
+
+/* Word 2 */
+#define TXDESC_ACK_REPORT		BIT(19)
+#define TXDESC_AMPDU_DENSITY_SHIFT	20
+
+/* Word 3 */
+#define TXDESC_SEQ_SHIFT		16
+#define TXDESC_SEQ_MASK			0x0fff0000
+
+/* Word 4 */
+#define TXDESC_QOS			BIT(6)
+#define TXDESC_HW_SEQ_ENABLE		BIT(7)
+#define TXDESC_USE_DRIVER_RATE		BIT(8)
+#define TXDESC_DISABLE_DATA_FB		BIT(10)
+#define TXDESC_CTS_SELF_ENABLE		BIT(11)
+#define TXDESC_RTS_CTS_ENABLE		BIT(12)
+#define TXDESC_HW_RTS_ENABLE		BIT(13)
+#define TXDESC_PRIME_CH_OFF_LOWER	BIT(20)
+#define TXDESC_PRIME_CH_OFF_UPPER	BIT(21)
+#define TXDESC_SHORT_PREAMBLE		BIT(24)
+#define TXDESC_DATA_BW			BIT(25)
+#define TXDESC_RTS_DATA_BW		BIT(27)
+#define TXDESC_RTS_PRIME_CH_OFF_LOWER	BIT(28)
+#define TXDESC_RTS_PRIME_CH_OFF_UPPER	BIT(29)
+
+/* Word 5 */
+#define TXDESC_RTS_RATE_SHIFT		0
+#define TXDESC_RTS_RATE_MASK		0x3f
+#define TXDESC_SHORT_GI			BIT(6)
+#define TXDESC_CCX_TAG			BIT(7)
+#define TXDESC_RETRY_LIMIT_ENABLE	BIT(17)
+#define TXDESC_RETRY_LIMIT_SHIFT	18
+#define TXDESC_RETRY_LIMIT_MASK		0x00fc0000
+
+/* Word 6 */
+#define TXDESC_MAX_AGG_SHIFT		11
+
+struct phy_rx_agc_info {
+#ifdef __LITTLE_ENDIAN
+	u8	gain:7, trsw:1;
+#else
+	u8	trsw:1, gain:7;
+#endif
+};
+
+struct rtl8723au_phy_stats {
+	struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS];
+	u8	ch_corr[RTL8723A_MAX_RF_PATHS];
+	u8	cck_sig_qual_ofdm_pwdb_all;
+	u8	cck_agc_rpt_ofdm_cfosho_a;
+	u8	cck_rpt_b_ofdm_cfosho_b;
+	u8	reserved_1;
+	u8	noise_power_db_msb;
+	u8	path_cfotail[RTL8723A_MAX_RF_PATHS];
+	u8	pcts_mask[RTL8723A_MAX_RF_PATHS];
+	s8	stream_rxevm[RTL8723A_MAX_RF_PATHS];
+	u8	path_rxsnr[RTL8723A_MAX_RF_PATHS];
+	u8	noise_power_db_lsb;
+	u8	reserved_2[3];
+	u8	stream_csi[RTL8723A_MAX_RF_PATHS];
+	u8	stream_target_csi[RTL8723A_MAX_RF_PATHS];
+	s8	sig_evm;
+	u8	reserved_3;
+
+#ifdef __LITTLE_ENDIAN
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+	u8	sgi_en:1;
+	u8	rxsc:2;
+	u8	idle_long:1;
+	u8	r_ant_train_en:1;
+	u8	antenna_select_b:1;
+	u8	antenna_select:1;
+#else	/*  _BIG_ENDIAN_ */
+	u8	antenna_select:1;
+	u8	antenna_select_b:1;
+	u8	r_ant_train_en:1;
+	u8	idle_long:1;
+	u8	rxsc:2;
+	u8	sgi_en:1;
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+#endif
+};
+
+/*
+ * Regs to backup
+ */
+#define RTL8XXXU_ADDA_REGS		16
+#define RTL8XXXU_MAC_REGS		4
+#define RTL8XXXU_BB_REGS		9
+
+struct rtl8xxxu_firmware_header {
+	__le16	signature;		/*  92C0: test chip; 92C,
+					    88C0: test chip;
+					    88C1: MP A-cut;
+					    92C1: MP A-cut */
+	u8	category;		/*  AP/NIC and USB/PCI */
+	u8	function;
+
+	__le16	major_version;		/*  FW Version */
+	u8	minor_version;		/*  FW Subversion, default 0x00 */
+	u8	reserved1;
+
+	u8	month;			/*  Release time Month field */
+	u8	date;			/*  Release time Date field */
+	u8	hour;			/*  Release time Hour field */
+	u8	minute;			/*  Release time Minute field */
+
+	__le16	ramcodesize;		/*  Size of RAM code */
+	u16	reserved2;
+
+	__le32	svn_idx;		/*  SVN entry index */
+	u32	reserved3;
+
+	u32	reserved4;
+	u32	reserved5;
+
+	u8	data[0];
+};
+
+/*
+ * The 8723au has 3 channel groups: 1-3, 4-9, and 10-14
+ */
+struct rtl8723au_idx {
+#ifdef __LITTLE_ENDIAN
+	int	a:4;
+	int	b:4;
+#else
+	int	b:4;
+	int	a:4;
+#endif
+} __attribute__((packed));
+
+struct rtl8723au_efuse {
+	__le16 rtl_id;
+	u8 res0[0xe];
+	u8 cck_tx_power_index_A[3];	/* 0x10 */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
+	u8 ht40_1s_tx_power_index_B[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u8 channel_plan;		/* 0x28 */
+	u8 tssi_a;
+	u8 thermal_meter;
+	u8 rf_regulatory;
+	u8 rf_option_2;
+	u8 rf_option_3;
+	u8 rf_option_4;
+	u8 res7;
+	u8 version			/* 0x30 */;
+	u8 customer_id_major;
+	u8 customer_id_minor;
+	u8 xtal_k;
+	u8 chipset;			/* 0x34 */
+	u8 res8[0x82];
+	u8 vid;				/* 0xb7 */
+	u8 res9;
+	u8 pid;				/* 0xb9 */
+	u8 res10[0x0c];
+	u8 mac_addr[ETH_ALEN];		/* 0xc6 */
+	u8 res11[2];
+	u8 vendor_name[7];
+	u8 res12[2];
+	u8 device_name[0x29];		/* 0xd7 */
+};
+
+struct rtl8192cu_efuse {
+	__le16 rtl_id;
+	__le16 hpon;
+	u8 res0[2];
+	__le16 clk;
+	__le16 testr;
+	__le16 vid;
+	__le16 did;
+	__le16 svid;
+	__le16 smid;						/* 0x10 */
+	u8 res1[4];
+	u8 mac_addr[ETH_ALEN];					/* 0x16 */
+	u8 res2[2];
+	u8 vendor_name[7];
+	u8 res3[3];
+	u8 device_name[0x14];					/* 0x28 */
+	u8 res4[0x1e];						/* 0x3c */
+	u8 cck_tx_power_index_A[3];				/* 0x5a */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];				/* 0x60 */
+	u8 ht40_1s_tx_power_index_B[3];
+	u8 ht40_2s_tx_power_index_diff[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];	/* 0x69 */
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];		/* 0x6f */
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u8 channel_plan;					/* 0x75 */
+	u8 tssi_a;
+	u8 tssi_b;
+	u8 thermal_meter;	/* xtal_k */			/* 0x78 */
+	u8 rf_regulatory;
+	u8 rf_option_2;
+	u8 rf_option_3;
+	u8 rf_option_4;
+	u8 res5[1];						/* 0x7d */
+	u8 version;
+	u8 customer_id;
+};
+
+struct rtl8xxxu_reg8val {
+	u16 reg;
+	u8 val;
+};
+
+struct rtl8xxxu_reg32val {
+	u16 reg;
+	u32 val;
+};
+
+struct rtl8xxxu_rfregval {
+	u8 reg;
+	u32 val;
+};
+
+enum rtl8xxxu_rfpath {
+	RF_A = 0,
+	RF_B = 1,
+};
+
+struct rtl8xxxu_rfregs {
+	u16 hssiparm1;
+	u16 hssiparm2;
+	u16 lssiparm;
+	u16 hspiread;
+	u16 lssiread;
+	u16 rf_sw_ctrl;
+};
+
+#define H2C_MAX_MBOX			4
+#define H2C_EXT				BIT(7)
+#define H2C_SET_POWER_MODE		1
+#define H2C_JOIN_BSS_REPORT		2
+#define  H2C_JOIN_BSS_DISCONNECT	0
+#define  H2C_JOIN_BSS_CONNECT		1
+#define H2C_SET_RSSI			5
+#define H2C_SET_RATE_MASK		(6 | H2C_EXT)
+
+struct h2c_cmd {
+	union {
+		struct {
+			u8 cmd;
+			u8 data[5];
+		} __packed cmd;
+		struct {
+			__le32 data;
+			__le16 ext;
+		} __packed raw;
+		struct {
+			u8 cmd;
+			u8 data;
+			u8 pad[4];
+		} __packed joinbss;
+		struct {
+			u8 cmd;
+			__le16 mask_hi;
+			u8 arg;
+			__le16 mask_lo;
+		} __packed ramask;
+	};
+};
+
+struct rtl8xxxu_fileops;
+
+struct rtl8xxxu_priv {
+	struct ieee80211_hw *hw;
+	struct usb_device *udev;
+	struct rtl8xxxu_fileops *fops;
+	u8 mac_addr[ETH_ALEN];
+	char chip_name[8];
+	u8 cck_tx_power_index_A[3];	/* 0x10 */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
+	u8 ht40_1s_tx_power_index_B[3];
+	u8 ht40_2s_tx_power_index_diff[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u32 chip_cut:4;
+	u32 rom_rev:4;
+	u32 has_wifi:1;
+	u32 has_bluetooth:1;
+	u32 enable_bluetooth:1;
+	u32 has_gps:1;
+	u32 hi_pa:1;
+	u32 vendor_umc:1;
+	u32 has_polarity_ctrl:1;
+	u32 has_eeprom:1;
+	u32 boot_eeprom:1;
+	u32 ep_tx_high_queue:1;
+	u32 ep_tx_normal_queue:1;
+	u32 ep_tx_low_queue:1;
+	u32 path_a_hi_power:1;
+	u32 path_a_rf_paths:4;
+	unsigned int pipe_interrupt;
+	unsigned int pipe_in;
+	unsigned int pipe_out[TXDESC_QUEUE_MAX];
+	u8 out_ep[RTL8XXXU_OUT_ENDPOINTS];
+	u8 path_a_ig_value;
+	u8 ep_tx_count;
+	u8 rf_paths;
+	u8 rx_paths;
+	u8 tx_paths;
+	u32 rf_mode_ag[2];
+	u32 rege94;
+	u32 rege9c;
+	u32 regeb4;
+	u32 regebc;
+	int next_mbox;
+	int nr_out_eps;
+
+	struct mutex h2c_mutex;
+
+	struct usb_anchor rx_anchor;
+	struct usb_anchor tx_anchor;
+	struct usb_anchor int_anchor;
+	struct rtl8xxxu_firmware_header *fw_data;
+	size_t fw_size;
+	struct mutex usb_buf_mutex;
+	union {
+		__le32 val32;
+		__le16 val16;
+		u8 val8;
+	} usb_buf;
+	union {
+		u8 raw[EFUSE_MAP_LEN_8723A];
+		struct rtl8723au_efuse efuse8723;
+		struct rtl8192cu_efuse efuse8192;
+	} efuse_wifi;
+	u32 adda_backup[RTL8XXXU_ADDA_REGS];
+	u32 mac_backup[RTL8XXXU_MAC_REGS];
+	u32 bb_backup[RTL8XXXU_BB_REGS];
+	u32 bb_recovery_backup[RTL8XXXU_BB_REGS];
+	u32 rtlchip;
+	u8 pi_enabled:1;
+	u8 iqk_initialized:1;
+	u8 int_buf[USB_INTR_CONTENT_LENGTH];
+};
+
+struct rtl8xxxu_rx_urb {
+	struct urb urb;
+	struct ieee80211_hw *hw;
+};
+
+struct rtl8xxxu_sta_priv {
+	bool short_preamble;
+};
+
+struct rtl8xxxu_fileops {
+	int (*parse_efuse) (struct rtl8xxxu_priv *priv);
+	int (*load_firmware) (struct rtl8xxxu_priv *priv);
+	int (*power_on) (struct rtl8xxxu_priv *priv);
+	int (*writeN) (struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len);
+};
diff --git a/drivers/net/wireless/rtl8xxxu_regs.h b/drivers/net/wireless/rtl8xxxu_regs.h
new file mode 100644
index 0000000..a7aa569
--- /dev/null
+++ b/drivers/net/wireless/rtl8xxxu_regs.h
@@ -0,0 +1,980 @@
+/*
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Register definitions taken from original Realtek rtl8723au driver
+ */
+
+/* 0x0000 ~ 0x00FF	System Configuration */
+#define REG_SYS_ISO_CTRL		0x0000
+#define  SYS_ISO_MD2PP			BIT(0)
+#define  SYS_ISO_ANALOG_IPS		BIT(5)
+#define  SYS_ISO_DIOR			BIT(9)
+#define  SYS_ISO_PWC_EV25V		BIT(14)
+#define  SYS_ISO_PWC_EV12V		BIT(15)
+
+#define REG_SYS_FUNC			0x0002
+#define  SYS_FUNC_BBRSTB		BIT(0)
+#define  SYS_FUNC_BB_GLB_RSTN		BIT(1)
+#define  SYS_FUNC_USBA			BIT(2)
+#define  SYS_FUNC_UPLL			BIT(3)
+#define  SYS_FUNC_USBD			BIT(4)
+#define  SYS_FUNC_DIO_PCIE		BIT(5)
+#define  SYS_FUNC_PCIEA			BIT(6)
+#define  SYS_FUNC_PPLL			BIT(7)
+#define  SYS_FUNC_PCIED			BIT(8)
+#define  SYS_FUNC_DIOE			BIT(9)
+#define  SYS_FUNC_CPU_ENABLE		BIT(10)
+#define  SYS_FUNC_DCORE			BIT(11)
+#define  SYS_FUNC_ELDR			BIT(12)
+#define  SYS_FUNC_DIO_RF		BIT(13)
+#define  SYS_FUNC_HWPDN			BIT(14)
+#define  SYS_FUNC_MREGEN		BIT(15)
+
+#define REG_APS_FSMCO			0x0004
+#define  APS_FSMCO_PFM_ALDN		BIT(1)
+#define  APS_FSMCO_PFM_WOWL		BIT(3)
+#define  APS_FSMCO_ENABLE_POWERDOWN	BIT(4)
+#define  APS_FSMCO_MAC_ENABLE		BIT(8)
+#define  APS_FSMCO_MAC_OFF		BIT(9)
+#define  APS_FSMCO_HW_SUSPEND		BIT(11)
+#define  APS_FSMCO_PCIE			BIT(12)
+#define  APS_FSMCO_HW_POWERDOWN		BIT(15)
+#define  APS_FSMCO_WLON_RESET		BIT(16)
+
+#define REG_SYS_CLKR			0x0008
+#define  SYS_CLK_ANAD16V_ENABLE		BIT(0)
+#define  SYS_CLK_ANA8M			BIT(1)
+#define  SYS_CLK_MACSLP			BIT(4)
+#define  SYS_CLK_LOADER_ENABLE		BIT(5)
+#define  SYS_CLK_80M_SSC_DISABLE	BIT(7)
+#define  SYS_CLK_80M_SSC_ENABLE_HO	BIT(8)
+#define  SYS_CLK_PHY_SSC_RSTB		BIT(9)
+#define  SYS_CLK_SEC_CLK_ENABLE		BIT(10)
+#define  SYS_CLK_MAC_CLK_ENABLE		BIT(11)
+#define  SYS_CLK_ENABLE			BIT(12)
+#define  SYS_CLK_RING_CLK_ENABLE	BIT(13)
+
+#define REG_9346CR			0x000a
+#define  EEPROM_BOOT			BIT(4)
+#define  EEPROM_ENABLE			BIT(5)
+
+#define REG_EE_VPD			0x000c
+#define REG_AFE_MISC			0x0010
+#define REG_SPS0_CTRL			0x0011
+#define REG_SPS_OCP_CFG			0x0018
+#define REG_RSV_CTRL			0x001c
+
+#define REG_RF_CTRL			0x001f
+#define  RF_ENABLE			BIT(0)
+#define  RF_RSTB			BIT(1)
+#define  RF_SDMRSTB			BIT(2)
+
+#define REG_LDOA15_CTRL			0x0020
+#define  LDOA15_ENABLE			BIT(0)
+#define  LDOA15_STANDBY			BIT(1)
+#define  LDOA15_OBUF			BIT(2)
+#define  LDOA15_REG_VOS			BIT(3)
+#define  LDOA15_VOADJ_SHIFT		4
+
+#define REG_LDOV12D_CTRL		0x0021
+#define  LDOV12D_ENABLE			BIT(0)
+#define  LDOV12D_STANDBY		BIT(1)
+#define  LDOV12D_VADJ_SHIFT		4
+
+#define REG_LDOHCI12_CTRL		0x0022
+
+#define REG_LPLDO_CTRL			0x0023
+#define  LPLDO_HSM			BIT(2)
+#define  LPLDO_LSM_DIS			BIT(3)
+
+#define REG_AFE_XTAL_CTRL		0x0024
+#define  AFE_XTAL_ENABLE		BIT(0)
+#define  AFE_XTAL_B_SELECT		BIT(1)
+#define  AFE_XTAL_GATE_USB		BIT(8)
+#define  AFE_XTAL_GATE_AFE		BIT(11)
+#define  AFE_XTAL_RF_GATE		BIT(14)
+#define  AFE_XTAL_GATE_DIG		BIT(17)
+#define  AFE_XTAL_BT_GATE		BIT(20)
+
+#define REG_AFE_PLL_CTRL		0x0028
+#define  AFE_PLL_ENABLE			BIT(0)
+#define  AFE_PLL_320_ENABLE		BIT(1)
+#define  APE_PLL_FREF_SELECT		BIT(2)
+#define  AFE_PLL_EDGE_SELECT		BIT(3)
+#define  AFE_PLL_WDOGB			BIT(4)
+#define  AFE_PLL_LPF_ENABLE		BIT(5)
+
+#define REG_MAC_PHY_CTRL		0x002c
+
+#define REG_EFUSE_CTRL			0x0030
+#define REG_EFUSE_TEST			0x0034
+#define  EFUSE_TRPT			BIT(7)
+	/*  00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
+#define  EFUSE_CELL_SEL			(BIT(8) | BIT(9))
+#define  EFUSE_LDOE25_ENABLE		BIT(31)
+#define  EFUSE_SELECT_MASK		0x0300
+#define  EFUSE_WIFI_SELECT		0x0000
+#define  EFUSE_BT0_SELECT		0x0100
+#define  EFUSE_BT1_SELECT		0x0200
+#define  EFUSE_BT2_SELECT		0x0300
+
+#define  EFUSE_ACCESS_ENABLE		0x69	/* RTL8723 only */
+#define  EFUSE_ACCESS_DISABLE		0x00	/* RTL8723 only */
+
+#define REG_PWR_DATA			0x0038
+#define REG_CAL_TIMER			0x003c
+#define REG_ACLK_MON			0x003e
+#define REG_GPIO_MUXCFG			0x0040
+#define REG_GPIO_IO_SEL			0x0042
+#define REG_MAC_PINMUX_CFG		0x0043
+#define REG_GPIO_PIN_CTRL		0x0044
+#define REG_GPIO_INTM			0x0048
+#define REG_LEDCFG0			0x004c
+#define REG_LEDCFG1			0x004d
+#define REG_LEDCFG2			0x004e
+#define  LEDCFG2_DPDT_SELECT		BIT(7)
+#define REG_LEDCFG3			0x004f
+#define REG_LEDCFG			REG_LEDCFG2
+#define REG_FSIMR			0x0050
+#define REG_FSISR			0x0054
+#define REG_HSIMR			0x0058
+#define REG_HSISR			0x005c
+/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */
+#define REG_GPIO_PIN_CTRL_2		0x0060
+/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */
+#define REG_GPIO_IO_SEL_2		0x0062
+
+/*  RTL8723 only WIFI/BT/GPS Multi-Function control source. */
+#define REG_MULTI_FUNC_CTRL		0x0068
+
+#define  MULTI_FN_WIFI_HW_PWRDOWN_EN	BIT(0)	/* Enable GPIO[9] as WiFi HW
+						   powerdown source */
+#define  MULTI_FN_WIFI_HW_PWRDOWN_SL	BIT(1)	/* WiFi HW powerdown polarity
+						   control */
+#define  MULTI_WIFI_FUNC_EN		BIT(2)	/* WiFi function enable */
+
+#define  MULTI_WIFI_HW_ROF_EN		BIT(3)	/* Enable GPIO[9] as WiFi RF HW
+						   powerdown source */
+#define  MULTI_BT_HW_PWRDOWN_EN		BIT(16)	/* Enable GPIO[11] as BT HW
+						   powerdown source */
+#define  MULTI_BT_HW_PWRDOWN_SL		BIT(17)	/* BT HW powerdown polarity
+						   control */
+#define  MULTI_BT_FUNC_EN		BIT(18)	/* BT function enable */
+#define  MULTI_BT_HW_ROF_EN		BIT(19)	/* Enable GPIO[11] as BT/GPS
+						   RF HW powerdown source */
+#define  MULTI_GPS_HW_PWRDOWN_EN	BIT(20)	/* Enable GPIO[10] as GPS HW
+						   powerdown source */
+#define  MULTI_GPS_HW_PWRDOWN_SL	BIT(21)	/* GPS HW powerdown polarity
+						   control */
+#define  MULTI_GPS_FUNC_EN		BIT(22)	/* GPS function enable */
+
+#define REG_MCU_FW_DL			0x0080
+#define  MCU_FW_DL_ENABLE		BIT(0)
+#define  MCU_FW_DL_READY		BIT(1)
+#define  MCU_FW_DL_CSUM_REPORT		BIT(2)
+#define  MCU_MAC_INIT_READY		BIT(3)
+#define  MCU_BB_INIT_READY		BIT(4)
+#define  MCU_RF_INIT_READY		BIT(5)
+#define  MCU_WINT_INIT_READY		BIT(6)
+#define  MCU_FW_RAM_SEL			BIT(7)	/* 1: RAM, 0:ROM */
+#define  MCU_CP_RESET			BIT(23)
+
+#define REG_HMBOX_EXT_0			0x0088
+#define REG_HMBOX_EXT_1			0x008a
+#define REG_HMBOX_EXT_2			0x008c
+#define REG_HMBOX_EXT_3			0x008e
+/*  Host suspend counter on FPGA platform */
+#define REG_HOST_SUSP_CNT		0x00bc
+/*  Efuse access protection for RTL8723 */
+#define REG_EFUSE_ACCESS		0x00cf
+#define REG_BIST_SCAN			0x00d0
+#define REG_BIST_RPT			0x00d4
+#define REG_BIST_ROM_RPT		0x00d8
+#define REG_USB_SIE_INTF		0x00e0
+#define REG_PCIE_MIO_INTF		0x00e4
+#define REG_PCIE_MIO_INTD		0x00e8
+#define REG_HPON_FSM			0x00ec
+#define  HPON_FSM_BONDING_MASK		(BIT(22) | BIT(23))
+#define  HPON_FSM_BONDING_1T2R		BIT(22)
+#define REG_SYS_CFG			0x00f0
+#define  SYS_CFG_XCLK_VLD		BIT(0)
+#define  SYS_CFG_ACLK_VLD		BIT(1)
+#define  SYS_CFG_UCLK_VLD		BIT(2)
+#define  SYS_CFG_PCLK_VLD		BIT(3)
+#define  SYS_CFG_PCIRSTB		BIT(4)
+#define  SYS_CFG_V15_VLD		BIT(5)
+#define  SYS_CFG_TRP_B15V_EN		BIT(7)
+#define  SYS_CFG_SIC_IDLE		BIT(8)
+#define  SYS_CFG_BD_MAC2		BIT(9)
+#define  SYS_CFG_BD_MAC1		BIT(10)
+#define  SYS_CFG_IC_MACPHY_MODE		BIT(11)
+#define  SYS_CFG_CHIP_VER		(BIT(12) | BIT(13) | BIT(14) | BIT(15))
+#define  SYS_CFG_BT_FUNC		BIT(16)
+#define  SYS_CFG_VENDOR_ID		BIT(19)
+#define  SYS_CFG_PAD_HWPD_IDN		BIT(22)
+#define  SYS_CFG_TRP_VAUX_EN		BIT(23)
+#define  SYS_CFG_TRP_BT_EN		BIT(24)
+#define  SYS_CFG_BD_PKG_SEL		BIT(25)
+#define  SYS_CFG_BD_HCI_SEL		BIT(26)
+#define  SYS_CFG_TYPE_ID		BIT(27)
+#define  SYS_CFG_RTL_ID			BIT(23) /*  TestChip ID,
+						    1:Test(RLE); 0:MP(RL) */
+#define  SYS_CFG_SPS_SEL		BIT(24) /*  1:LDO regulator mode;
+						    0:Switching regulator mode*/
+#define  SYS_CFG_CHIP_VERSION_MASK	0xf000	/* Bit 12 - 15 */
+#define  SYS_CFG_CHIP_VERSION_SHIFT	12
+
+#define REG_GPIO_OUTSTS			0x00f4	/*  For RTL8723 only. */
+#define  GPIO_EFS_HCI_SEL		(BIT(0) | BIT(1))
+#define  GPIO_PAD_HCI_SEL		(BIT(2) | BIT(3))
+#define  GPIO_HCI_SEL			(BIT(4) | BIT(5))
+#define  GPIO_PKG_SEL_HCI		BIT(6)
+#define  GPIO_FEN_GPS			BIT(7)
+#define  GPIO_FEN_BT			BIT(8)
+#define  GPIO_FEN_WL			BIT(9)
+#define  GPIO_FEN_PCI			BIT(10)
+#define  GPIO_FEN_USB			BIT(11)
+#define  GPIO_BTRF_HWPDN_N		BIT(12)
+#define  GPIO_WLRF_HWPDN_N		BIT(13)
+#define  GPIO_PDN_BT_N			BIT(14)
+#define  GPIO_PDN_GPS_N			BIT(15)
+#define  GPIO_BT_CTL_HWPDN		BIT(16)
+#define  GPIO_GPS_CTL_HWPDN		BIT(17)
+#define  GPIO_PPHY_SUSB			BIT(20)
+#define  GPIO_UPHY_SUSB			BIT(21)
+#define  GPIO_PCI_SUSEN			BIT(22)
+#define  GPIO_USB_SUSEN			BIT(23)
+#define  GPIO_RF_RL_ID			(BIT(31) | BIT(30) | BIT(29) | BIT(28))
+
+/* 0x0100 ~ 0x01FF	MACTOP General Configuration */
+#define REG_CR				0x0100
+#define  CR_HCI_TXDMA_ENABLE		BIT(0)
+#define  CR_HCI_RXDMA_ENABLE		BIT(1)
+#define  CR_TXDMA_ENABLE		BIT(2)
+#define  CR_RXDMA_ENABLE		BIT(3)
+#define  CR_PROTOCOL_ENABLE		BIT(4)
+#define  CR_SCHEDULE_ENABLE		BIT(5)
+#define  CR_MAC_TX_ENABLE		BIT(6)
+#define  CR_MAC_RX_ENABLE		BIT(7)
+#define  CR_SW_BEACON_ENABLE		BIT(8)
+#define  CR_SECURITY_ENABLE		BIT(9)
+#define  CR_CALTIMER_ENABLE		BIT(10)
+
+/* Media Status Register */
+#define REG_MSR				0x0102
+#define  MSR_LINKTYPE_MASK		0x3
+#define  MSR_LINKTYPE_NONE		0x0
+#define  MSR_LINKTYPE_ADHOC		0x1
+#define  MSR_LINKTYPE_STATION		0x2
+#define  MSR_LINKTYPE_AP		0x3
+
+#define REG_PBP				0x0104
+#define  PBP_PAGE_SIZE_RX_SHIFT		0
+#define  PBP_PAGE_SIZE_TX_SHIFT		4
+#define  PBP_PAGE_SIZE_64		0x0
+#define  PBP_PAGE_SIZE_128		0x1
+#define  PBP_PAGE_SIZE_256		0x2
+#define  PBP_PAGE_SIZE_512		0x3
+#define  PBP_PAGE_SIZE_1024		0x4
+
+#define REG_TRXDMA_CTRL			0x010c
+#define  TRXDMA_CTRL_VOQ_SHIFT		4
+#define  TRXDMA_CTRL_VIQ_SHIFT		6
+#define  TRXDMA_CTRL_BEQ_SHIFT		8
+#define  TRXDMA_CTRL_BKQ_SHIFT		10
+#define  TRXDMA_CTRL_MGQ_SHIFT		12
+#define  TRXDMA_CTRL_HIQ_SHIFT		14
+#define  TRXDMA_QUEUE_LOW		1
+#define  TRXDMA_QUEUE_NORMAL		2
+#define  TRXDMA_QUEUE_HIGH		3
+
+#define REG_TRXFF_BNDY			0x0114
+#define REG_TRXFF_STATUS		0x0118
+#define REG_RXFF_PTR			0x011c
+#define REG_HIMR			0x0120
+#define REG_HISR			0x0124
+#define REG_HIMRE			0x0128
+#define REG_HISRE			0x012c
+#define REG_CPWM			0x012f
+#define REG_FWIMR			0x0130
+#define REG_FWISR			0x0134
+#define REG_PKTBUF_DBG_CTRL		0x0140
+#define REG_PKTBUF_DBG_DATA_L		0x0144
+#define REG_PKTBUF_DBG_DATA_H		0x0148
+
+#define REG_TC0_CTRL			0x0150
+#define REG_TC1_CTRL			0x0154
+#define REG_TC2_CTRL			0x0158
+#define REG_TC3_CTRL			0x015c
+#define REG_TC4_CTRL			0x0160
+#define REG_TCUNIT_BASE			0x0164
+#define REG_MBIST_START			0x0174
+#define REG_MBIST_DONE			0x0178
+#define REG_MBIST_FAIL			0x017c
+#define REG_C2HEVT_MSG_NORMAL		0x01a0
+#define REG_C2HEVT_CLEAR		0x01af
+#define REG_C2HEVT_MSG_TEST		0x01b8
+#define REG_MCUTST_1			0x01c0
+#define REG_FMTHR			0x01c8
+#define REG_HMTFR			0x01cc
+#define REG_HMBOX_0			0x01d0
+#define REG_HMBOX_1			0x01d4
+#define REG_HMBOX_2			0x01d8
+#define REG_HMBOX_3			0x01dc
+
+#define REG_LLT_INIT			0x01e0
+#define  LLT_OP_INACTIVE		0x0
+#define  LLT_OP_WRITE			(0x1 << 30)
+#define  LLT_OP_READ			(0x2 << 30)
+#define  LLT_OP_MASK			(0x3 << 30)
+
+#define REG_BB_ACCEESS_CTRL		0x01e8
+#define REG_BB_ACCESS_DATA		0x01ec
+
+/* 0x0200 ~ 0x027F	TXDMA Configuration */
+#define REG_RQPN			0x0200
+#define  RQPN_HI_PQ_SHIFT		0
+#define  RQPN_LO_PQ_SHIFT		8
+#define  RQPN_NORM_PQ_SHIFT		16
+#define  RQPN_LOAD			BIT(31)
+
+#define REG_FIFOPAGE			0x0204
+#define REG_TDECTRL			0x0208
+#define REG_TXDMA_OFFSET_CHK		0x020c
+#define REG_TXDMA_STATUS		0x0210
+#define REG_RQPN_NPQ			0x0214
+
+/* 0x0280 ~ 0x02FF	RXDMA Configuration */
+#define REG_RXDMA_AGG_PG_TH		0x0280
+#define REG_RXPKT_NUM			0x0284
+#define REG_RXDMA_STATUS		0x0288
+
+#define REG_RF_BB_CMD_ADDR		0x02c0
+#define REG_RF_BB_CMD_DATA		0x02c4
+
+/*  spec version 11 */
+/* 0x0400 ~ 0x047F	Protocol Configuration */
+#define REG_VOQ_INFORMATION		0x0400
+#define REG_VIQ_INFORMATION		0x0404
+#define REG_BEQ_INFORMATION		0x0408
+#define REG_BKQ_INFORMATION		0x040c
+#define REG_MGQ_INFORMATION		0x0410
+#define REG_HGQ_INFORMATION		0x0414
+#define REG_BCNQ_INFORMATION		0x0418
+
+#define REG_CPU_MGQ_INFORMATION		0x041c
+#define REG_FWHW_TXQ_CTRL		0x0420
+#define  FWHW_TXQ_CTRL_AMPDU_RETRY	BIT(7)
+#define  FWHW_TXQ_CTRL_XMIT_MGMT_ACK	BIT(12)
+
+#define REG_HWSEQ_CTRL			0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
+#define REG_TXPKTBUF_MGQ_BDNY		0x0425
+#define REG_LIFETIME_EN			0x0426
+#define REG_MULTI_BCNQ_OFFSET		0x0427
+
+#define REG_SPEC_SIFS			0x0428
+#define  SPEC_SIFS_CCK_MASK		0x00ff
+#define  SPEC_SIFS_CCK_SHIFT		0
+#define  SPEC_SIFS_OFDM_MASK		0xff00
+#define  SPEC_SIFS_OFDM_SHIFT		8
+
+#define REG_RETRY_LIMIT			0x042a
+#define  RETRY_LIMIT_LONG_SHIFT		0
+#define  RETRY_LIMIT_LONG_MASK		0x003f
+#define  RETRY_LIMIT_SHORT_SHIFT	8
+#define  RETRY_LIMIT_SHORT_MASK		0x3f00
+
+#define REG_DARFRC			0x0430
+#define REG_RARFRC			0x0438
+#define REG_RESPONSE_RATE_SET		0x0440
+#define  RESPONSE_RATE_BITMAP_ALL	0xfffff
+#define  RESPONSE_RATE_RRSR_CCK_ONLY_1M	0xffff1
+#define  RSR_1M				BIT(0)
+#define  RSR_2M				BIT(1)
+#define  RSR_5_5M			BIT(2)
+#define  RSR_11M			BIT(3)
+#define  RSR_6M				BIT(4)
+#define  RSR_9M				BIT(5)
+#define  RSR_12M			BIT(6)
+#define  RSR_18M			BIT(7)
+#define  RSR_24M			BIT(8)
+#define  RSR_36M			BIT(9)
+#define  RSR_48M			BIT(10)
+#define  RSR_54M			BIT(11)
+#define  RSR_MCS0			BIT(12)
+#define  RSR_MCS1			BIT(13)
+#define  RSR_MCS2			BIT(14)
+#define  RSR_MCS3			BIT(15)
+#define  RSR_MCS4			BIT(16)
+#define  RSR_MCS5			BIT(17)
+#define  RSR_MCS6			BIT(18)
+#define  RSR_MCS7			BIT(19)
+#define  RSR_RSC_LOWER_SUB_CHANNEL	BIT(21)	/* 0x200000 */
+#define  RSR_RSC_UPPER_SUB_CHANNEL	BIT(22)	/* 0x400000 */
+#define  RSR_RSC_BANDWIDTH_40M		(RSR_RSC_UPPER_SUB_CHANNEL | \
+					 RSR_RSC_LOWER_SUB_CHANNEL)
+#define  RSR_ACK_SHORT_PREAMBLE		BIT(23)
+
+#define REG_ARFR0			0x0444
+#define REG_ARFR1			0x0448
+#define REG_ARFR2			0x044c
+#define REG_ARFR3			0x0450
+#define REG_AGGLEN_LMT			0x0458
+#define REG_AMPDU_MIN_SPACE		0x045c
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD	0x045d
+#define REG_FAST_EDCA_CTRL		0x0460
+#define REG_RD_RESP_PKT_TH		0x0463
+#define REG_INIRTS_RATE_SEL		0x0480
+#define REG_INIDATA_RATE_SEL		0x0484
+
+#define REG_POWER_STATUS		0x04a4
+#define REG_POWER_STAGE1		0x04b4
+#define REG_POWER_STAGE2		0x04b8
+#define REG_PKT_VO_VI_LIFE_TIME		0x04c0
+#define REG_PKT_BE_BK_LIFE_TIME		0x04c2
+#define REG_STBC_SETTING		0x04c4
+#define REG_PROT_MODE_CTRL		0x04c8
+#define REG_MAX_AGGR_NUM		0x04ca
+#define REG_RTS_MAX_AGGR_NUM		0x04cb
+#define REG_BAR_MODE_CTRL		0x04cc
+#define REG_RA_TRY_RATE_AGG_LMT		0x04cf
+#define REG_NQOS_SEQ			0x04dc
+#define REG_QOS_SEQ			0x04de
+#define REG_NEED_CPU_HANDLE		0x04e0
+#define REG_PKT_LOSE_RPT		0x04e1
+#define REG_PTCL_ERR_STATUS		0x04e2
+#define REG_DUMMY			0x04fc
+
+/* 0x0500 ~ 0x05FF	EDCA Configuration */
+#define REG_EDCA_VO_PARAM		0x0500
+#define REG_EDCA_VI_PARAM		0x0504
+#define REG_EDCA_BE_PARAM		0x0508
+#define REG_EDCA_BK_PARAM		0x050c
+#define  EDCA_PARAM_ECW_MIN_SHIFT	8
+#define  EDCA_PARAM_ECW_MAX_SHIFT	12
+#define  EDCA_PARAM_TXOP_SHIFT		16
+#define REG_BEACON_TCFG			0x0510
+#define REG_PIFS			0x0512
+#define REG_RDG_PIFS			0x0513
+#define REG_SIFS_CCK			0x0514
+#define REG_SIFS_OFDM			0x0516
+#define REG_TSFTR_SYN_OFFSET		0x0518
+#define REG_AGGR_BREAK_TIME		0x051a
+#define REG_SLOT			0x051b
+#define REG_TX_PTCL_CTRL		0x0520
+#define REG_TXPAUSE			0x0522
+#define REG_DIS_TXREQ_CLR		0x0523
+#define REG_RD_CTRL			0x0524
+#define REG_TBTT_PROHIBIT		0x0540
+#define REG_RD_NAV_NXT			0x0544
+#define REG_NAV_PROT_LEN		0x0546
+
+#define REG_BEACON_CTRL			0x0550
+#define REG_BEACON_CTRL_1		0x0551
+#define  BEACON_ATIM			BIT(0)
+#define  BEACON_CTRL_MBSSID		BIT(1)
+#define  BEACON_CTRL_TX_BEACON_RPT	BIT(2)
+#define  BEACON_FUNCTION_ENABLE		BIT(3)
+#define  BEACON_DISABLE_TSF_UPDATE	BIT(4)
+
+#define REG_MBID_NUM			0x0552
+#define REG_DUAL_TSF_RST		0x0553
+#define  DUAL_TSF_RESET_TSF0		BIT(0)
+#define  DUAL_TSF_RESET_TSF1		BIT(1)
+#define  DUAL_TSF_RESET_P2P		BIT(4)
+#define  DUAL_TSF_TX_OK			BIT(5)
+
+/*  The same as REG_MBSSID_BCN_SPACE */
+#define REG_BCN_INTERVAL		0x0554
+#define REG_MBSSID_BCN_SPACE		0x0554
+
+#define REG_DRIVER_EARLY_INT		0x0558
+#define  DRIVER_EARLY_INT_TIME		5
+
+#define REG_BEACON_DMA_TIME		0x0559
+#define  BEACON_DMA_ATIME_INT_TIME	2
+
+#define REG_ATIMWND			0x055a
+#define REG_BCN_MAX_ERR			0x055d
+#define REG_RXTSF_OFFSET_CCK		0x055e
+#define REG_RXTSF_OFFSET_OFDM		0x055f
+#define REG_TSFTR			0x0560
+#define REG_TSFTR1			0x0568
+#define REG_INIT_TSFTR			0x0564
+#define REG_ATIMWND_1			0x0570
+#define REG_PSTIMER			0x0580
+#define REG_TIMER0			0x0584
+#define REG_TIMER1			0x0588
+#define REG_ACM_HW_CTRL			0x05c0
+#define  ACM_HW_CTRL_BK			BIT(0)
+#define  ACM_HW_CTRL_BE			BIT(1)
+#define  ACM_HW_CTRL_VI			BIT(2)
+#define  ACM_HW_CTRL_VO			BIT(3)
+#define REG_ACM_RST_CTRL		0x05c1
+#define REG_ACMAVG			0x05c2
+#define REG_VO_ADMTIME			0x05c4
+#define REG_VI_ADMTIME			0x05c6
+#define REG_BE_ADMTIME			0x05c8
+#define REG_EDCA_RANDOM_GEN		0x05cc
+#define REG_SCH_TXCMD			0x05d0
+
+/* define REG_FW_TSF_SYNC_CNT		0x04a0 */
+#define REG_FW_RESET_TSF_CNT_1		0x05fc
+#define REG_FW_RESET_TSF_CNT_0		0x05fd
+#define REG_FW_BCN_DIS_CNT		0x05fe
+
+/* 0x0600 ~ 0x07FF  WMAC Configuration */
+#define REG_APSD_CTRL			0x0600
+#define  APSD_CTRL_OFF			BIT(6)
+#define  APSD_CTRL_OFF_STATUS		BIT(7)
+#define REG_BW_OPMODE			0x0603
+#define  BW_OPMODE_20MHZ		BIT(2)
+#define  BW_OPMODE_5G			BIT(1)
+#define  BW_OPMODE_11J			BIT(0)
+
+#define REG_TCR				0x0604
+
+/* Receive Configuration Register */
+#define REG_RCR				0x0608
+#define  RCR_ACCEPT_AP			BIT(0)  /* Accept all unicast packet */
+#define  RCR_ACCEPT_PHYS_MATCH		BIT(1)  /* Accept phys match packet */
+#define  RCR_ACCEPT_MCAST		BIT(2)
+#define  RCR_ACCEPT_BCAST		BIT(3)
+#define  RCR_ACCEPT_ADDR3		BIT(4)  /* Accept address 3 match
+						 packet */
+#define  RCR_ACCEPT_PM			BIT(5)  /* Accept power management
+						 packet */
+#define  RCR_CHECK_BSSID_MATCH		BIT(6)  /* Accept BSSID match packet */
+#define  RCR_CHECK_BSSID_BEACON		BIT(7)  /* Accept BSSID match packet
+						 (Rx beacon, probe rsp) */
+#define  RCR_ACCEPT_CRC32		BIT(8)  /* Accept CRC32 error packet */
+#define  RCR_ACCEPT_ICV			BIT(9)  /* Accept ICV error packet */
+#define  RCR_ACCEPT_DATA_FRAME		BIT(11)
+#define  RCR_ACCEPT_CTRL_FRAME		BIT(12)
+#define  RCR_ACCEPT_MGMT_FRAME		BIT(13)
+#define  RCR_HTC_LOC_CTRL		BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */
+#define  RCR_MFBEN			BIT(22)
+#define  RCR_LSIGEN			BIT(23)
+#define  RCR_MULTI_BSSID_ENABLE		BIT(24) /* Enable Multiple BssId */
+#define  RCR_ACCEPT_BA_SSN		BIT(27) /* Accept BA SSN */
+#define  RCR_APPEND_PHYSTAT		BIT(28)
+#define  RCR_APPEND_ICV			BIT(29)
+#define  RCR_APPEND_MIC			BIT(30)
+#define  RCR_APPEND_FCS			BIT(31) /* WMAC append FCS after */
+
+#define REG_RX_PKT_LIMIT		0x060c
+#define REG_RX_DLK_TIME			0x060d
+#define REG_RX_DRVINFO_SZ		0x060f
+
+#define REG_MACID			0x0610
+#define REG_BSSID			0x0618
+#define REG_MAR				0x0620
+#define REG_MBIDCAMCFG			0x0628
+
+#define REG_USTIME_EDCA			0x0638
+#define REG_MAC_SPEC_SIFS		0x063a
+
+/*  20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
+	/*  [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
+#define REG_R2T_SIFS			0x063c
+	/*  [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
+#define REG_T2T_SIFS			0x063e
+#define REG_ACKTO			0x0640
+#define REG_CTS2TO			0x0641
+#define REG_EIFS			0x0642
+
+/* WMA, BA, CCX */
+#define REG_NAV_CTRL			0x0650
+/* In units of 128us */
+#define REG_NAV_UPPER			0x0652
+#define  NAV_UPPER_UNIT			128
+
+#define REG_BACAMCMD			0x0654
+#define REG_BACAMCONTENT		0x0658
+#define REG_LBDLY			0x0660
+#define REG_FWDLY			0x0661
+#define REG_RXERR_RPT			0x0664
+#define REG_WMAC_TRXPTCL_CTL		0x0668
+
+/*  Security */
+#define REG_CAM_CMD			0x0670
+#define  CAM_CMD_POLLING		BIT(31)
+#define  CAM_CMD_WRITE			BIT(16)
+#define  CAM_CMD_KEY_SHIFT		3
+#define REG_CAM_WRITE			0x0674
+#define  CAM_WRITE_VALID		BIT(15)
+#define REG_CAM_READ			0x0678
+#define REG_CAM_DEBUG			0x067c
+#define REG_SECURITY_CFG		0x0680
+#define  SEC_CFG_TX_USE_DEFKEY		BIT(0)
+#define  SEC_CFG_RX_USE_DEFKEY		BIT(1)
+#define  SEC_CFG_TX_SEC_ENABLE		BIT(2)
+#define  SEC_CFG_RX_SEC_ENABLE		BIT(3)
+#define  SEC_CFG_SKBYA2			BIT(4)
+#define  SEC_CFG_NO_SKMC		BIT(5)
+#define  SEC_CFG_TXBC_USE_DEFKEY	BIT(6)
+#define  SEC_CFG_RXBC_USE_DEFKEY	BIT(7)
+
+/*  Power */
+#define REG_WOW_CTRL			0x0690
+#define REG_PSSTATUS			0x0691
+#define REG_PS_RX_INFO			0x0692
+#define REG_LPNAV_CTRL			0x0694
+#define REG_WKFMCAM_CMD			0x0698
+#define REG_WKFMCAM_RWD			0x069c
+#define REG_RXFLTMAP0			0x06a0
+#define REG_RXFLTMAP1			0x06a2
+#define REG_RXFLTMAP2			0x06a4
+#define REG_BCN_PSR_RPT			0x06a8
+#define REG_CALB32K_CTRL		0x06ac
+#define REG_PKT_MON_CTRL		0x06b4
+#define REG_BT_COEX_TABLE		0x06c0
+#define REG_WMAC_RESP_TXINFO		0x06d8
+
+#define REG_MACID1			0x0700
+#define REG_BSSID1			0x0708
+
+#define REG_FPGA0_RF_MODE		0x0800
+#define  FPGA_RF_MODE			BIT(0)
+#define  FPGA_RF_MODE_JAPAN		BIT(1)
+#define  FPGA_RF_MODE_CCK		BIT(24)
+#define  FPGA_RF_MODE_OFDM		BIT(25)
+
+#define REG_FPGA0_TX_INFO		0x0804
+#define REG_FPGA0_PSD_FUNC		0x0808
+#define REG_FPGA0_TX_GAIN		0x080c
+#define REG_FPGA0_RF_TIMING1		0x0810
+#define REG_FPGA0_RF_TIMING2		0x0814
+#define REG_FPGA0_POWER_SAVE		0x0818
+#define  FPGA0_PS_LOWER_CHANNEL		BIT(26)
+#define  FPGA0_PS_UPPER_CHANNEL		BIT(27)
+
+#define REG_FPGA0_XA_HSSI_PARM1		0x0820	/* RF 3 wire register */
+#define  FPGA0_HSSI_PARM1_PI		BIT(8)
+#define REG_FPGA0_XA_HSSI_PARM2		0x0824
+#define REG_FPGA0_XB_HSSI_PARM1		0x0828
+#define REG_FPGA0_XB_HSSI_PARM2		0x082c
+#define  FPGA0_HSSI_3WIRE_DATA_LEN	0x800
+#define  FPGA0_HSSI_3WIRE_ADDR_LEN	0x400
+#define  FPGA0_HSSI_PARM2_ADDR_SHIFT	23
+#define  FPGA0_HSSI_PARM2_ADDR_MASK	0x7f800000	/* 0xff << 23 */
+#define  FPGA0_HSSI_PARM2_CCK_HIGH_PWR	BIT(9)
+#define  FPGA0_HSSI_PARM2_EDGE_READ	BIT(31)
+
+#define REG_TX_AGC_B_RATE18_06		0x0830
+#define REG_TX_AGC_B_RATE54_24		0x0834
+#define REG_TX_AGC_B_CCK1_55_MCS32	0x0838
+#define REG_TX_AGC_B_MCS03_MCS00	0x083c
+
+#define REG_FPGA0_XA_LSSI_PARM		0x0840
+#define REG_FPGA0_XB_LSSI_PARM		0x0844
+#define  FPGA0_LSSI_PARM_ADDR_SHIFT	20
+#define  FPGA0_LSSI_PARM_ADDR_MASK	0x0ff00000
+#define  FPGA0_LSSI_PARM_DATA_MASK	0x000fffff
+
+#define REG_TX_AGC_B_MCS07_MCS04	0x0848
+#define REG_TX_AGC_B_MCS11_MCS08	0x084c
+
+#define REG_FPGA0_XCD_SWITCH_CTRL	0x085c
+
+#define REG_FPGA0_XA_RF_INT_OE		0x0860	/* RF Channel switch */
+#define REG_FPGA0_XB_RF_INT_OE		0x0864
+#define  FPGA0_INT_OE_ANTENNA_AB_OPEN	0x000
+#define  FPGA0_INT_OE_ANTENNA_A		0x100
+#define  FPGA0_INT_OE_ANTENNA_B		0x200
+#define  FPGA0_INT_OE_ANTENNA_MASK	0x300
+
+#define REG_TX_AGC_B_MCS15_MCS12	0x0868
+#define REG_TX_AGC_B_CCK11_A_CCK2_11	0x086c
+
+#define REG_FPGA0_XAB_RF_SW_CTRL	0x0870
+#define REG_FPGA0_XA_RF_SW_CTRL		0x0870	/* 16 bit */
+#define REG_FPGA0_XB_RF_SW_CTRL		0x0872	/* 16 bit */
+#define REG_FPGA0_XCD_RF_SW_CTRL	0x0874
+#define REG_FPGA0_XC_RF_SW_CTRL		0x0874	/* 16 bit */
+#define REG_FPGA0_XD_RF_SW_CTRL		0x0876	/* 16 bit */
+#define  FPGA0_RF_3WIRE_DATA		BIT(0)
+#define  FPGA0_RF_3WIRE_CLOC		BIT(1)
+#define  FPGA0_RF_3WIRE_LOAD		BIT(2)
+#define  FPGA0_RF_3WIRE_RW		BIT(3)
+#define  FPGA0_RF_3WIRE_MASK		0xf
+#define  FPGA0_RF_RFENV			BIT(4)
+#define  FPGA0_RF_TRSW			BIT(5)	/* Useless now */
+#define  FPGA0_RF_TRSWB			BIT(6)
+#define  FPGA0_RF_ANTSW			BIT(8)
+#define  FPGA0_RF_ANTSWB		BIT(9)
+#define  FPGA0_RF_PAPE			BIT(10)
+#define  FPGA0_RF_PAPE5G		BIT(11)
+#define  FPGA0_RF_BD_CTRL_SHIFT		16
+
+#define REG_FPGA0_XAB_RF_PARM		0x0878	/* Antenna select path in ODM */
+#define REG_FPGA0_XA_RF_PARM		0x0878	/* 16 bit */
+#define REG_FPGA0_XB_RF_PARM		0x087a	/* 16 bit */
+#define REG_FPGA0_XCD_RF_PARM		0x087c
+#define REG_FPGA0_XC_RF_PARM		0x087c	/* 16 bit */
+#define REG_FPGA0_XD_RF_PARM		0x087e	/* 16 bit */
+#define  FPGA0_RF_PARM_RFA_ENABLE	BIT(1)
+#define  FPGA0_RF_PARM_RFB_ENABLE	BIT(17)
+#define  FPGA0_RF_PARM_CLK_GATE		BIT(31)
+
+#define REG_FPGA0_ANALOG1		0x0880
+#define REG_FPGA0_ANALOG2		0x0884
+#define  FPGA0_ANALOG2_20MHZ		BIT(10)
+#define REG_FPGA0_ANALOG3		0x0888
+#define REG_FPGA0_ANALOG4		0x088c
+
+#define REG_FPGA0_XA_LSSI_READBACK	0x08a0	/* Tranceiver LSSI Readback */
+#define REG_FPGA0_XB_LSSI_READBACK	0x08a4
+#define REG_HSPI_XA_READBACK		0x08b8	/* Transceiver A HSPI read */
+#define REG_HSPI_XB_READBACK		0x08bc	/* Transceiver B HSPI read */
+
+#define REG_FPGA1_RF_MODE		0x0900
+
+#define REG_FPGA1_TX_INFO		0x090c
+
+#define REG_CCK0_SYSTEM			0x0a00
+#define  CCK0_SIDEBAND			BIT(4)
+
+#define REG_CCK0_AFE_SETTING		0x0a04
+
+#define REG_CONFIG_ANT_A		0x0b68
+#define REG_CONFIG_ANT_B		0x0b6c
+
+#define REG_OFDM0_TRX_PATH_ENABLE	0x0c04
+#define OFDM_RF_PATH_RX_MASK		0x0f
+#define OFDM_RF_PATH_RX_A		BIT(0)
+#define OFDM_RF_PATH_RX_B		BIT(1)
+#define OFDM_RF_PATH_RX_C		BIT(2)
+#define OFDM_RF_PATH_RX_D		BIT(3)
+#define OFDM_RF_PATH_TX_MASK		0xf0
+#define OFDM_RF_PATH_TX_A		BIT(4)
+#define OFDM_RF_PATH_TX_B		BIT(5)
+#define OFDM_RF_PATH_TX_C		BIT(6)
+#define OFDM_RF_PATH_TX_D		BIT(7)
+
+#define REG_OFDM0_TR_MUX_PAR		0x0c08
+
+#define REG_OFDM0_XA_RX_IQ_IMBALANCE	0x0c14
+#define REG_OFDM0_XB_RX_IQ_IMBALANCE	0x0c1c
+
+#define REG_OFDM0_ENERGY_CCA_THRES	0x0c4c
+
+#define REG_OFDM0_XA_AGC_CORE1		0x0c50
+#define REG_OFDM0_XA_AGC_CORE2		0x0c54
+#define REG_OFDM0_XB_AGC_CORE1		0x0c58
+#define REG_OFDM0_XB_AGC_CORE2		0x0c5c
+#define REG_OFDM0_XC_AGC_CORE1		0x0c60
+#define REG_OFDM0_XC_AGC_CORE2		0x0c64
+#define REG_OFDM0_XD_AGC_CORE1		0x0c68
+#define REG_OFDM0_XD_AGC_CORE2		0x0c6c
+#define  OFDM0_X_AGC_CORE1_IGI_MASK	0x0000007F
+
+#define REG_OFDM0_AGC_PARM1		0x0c70
+
+#define REG_OFDM0_AGCR_SSI_TABLE	0x0c78
+
+#define REG_OFDM0_XA_TX_IQ_IMBALANCE	0x0c80
+#define REG_OFDM0_XB_TX_IQ_IMBALANCE	0x0c88
+#define REG_OFDM0_XC_TX_IQ_IMBALANCE	0x0c90
+#define REG_OFDM0_XD_TX_IQ_IMBALANCE	0x0c98
+
+#define REG_OFDM0_XC_TX_AFE		0x0c94
+#define REG_OFDM0_XD_TX_AFE		0x0c9c
+
+#define REG_OFDM0_RX_IQ_EXT_ANTA	0x0ca0
+
+#define REG_OFDM1_LSTF			0x0d00
+#define  OFDM_LSTF_PRIME_CH_LOW		BIT(10)
+#define  OFDM_LSTF_PRIME_CH_HIGH	BIT(11)
+#define  OFDM_LSTF_PRIME_CH_MASK	(OFDM_LSTF_PRIME_CH_LOW | \
+					 OFDM_LSTF_PRIME_CH_HIGH)
+#define  OFDM_LSTF_CONTINUE_TX		BIT(28)
+#define  OFDM_LSTF_SINGLE_CARRIER	BIT(29)
+#define  OFDM_LSTF_SINGLE_TONE		BIT(30)
+#define  OFDM_LSTF_MASK			0x70000000
+
+#define REG_OFDM1_TRX_PATH_ENABLE	0x0d04
+
+#define REG_TX_AGC_A_RATE18_06		0x0e00
+#define REG_TX_AGC_A_RATE54_24		0x0e04
+#define REG_TX_AGC_A_CCK1_MCS32		0x0e08
+#define REG_TX_AGC_A_MCS03_MCS00	0x0e10
+#define REG_TX_AGC_A_MCS07_MCS04	0x0e14
+#define REG_TX_AGC_A_MCS11_MCS08	0x0e18
+#define REG_TX_AGC_A_MCS15_MCS12	0x0e1c
+
+#define REG_FPGA0_IQK			0x0e28
+
+#define REG_TX_IQK_TONE_A		0x0e30
+#define REG_RX_IQK_TONE_A		0x0e34
+#define REG_TX_IQK_PI_A			0x0e38
+#define REG_RX_IQK_PI_A			0x0e3c
+
+#define REG_TX_IQK			0x0e40
+#define REG_RX_IQK			0x0e44
+#define REG_IQK_AGC_PTS			0x0e48
+#define REG_IQK_AGC_RSP			0x0e4c
+#define REG_TX_IQK_TONE_B		0x0e50
+#define REG_RX_IQK_TONE_B		0x0e54
+#define REG_TX_IQK_PI_B			0x0e58
+#define REG_RX_IQK_PI_B			0x0e5c
+#define REG_IQK_AGC_CONT		0x0e60
+
+#define REG_BLUETOOTH			0x0e6c
+#define REG_RX_WAIT_CCA			0x0e70
+#define REG_TX_CCK_RFON			0x0e74
+#define REG_TX_CCK_BBON			0x0e78
+#define REG_TX_OFDM_RFON		0x0e7c
+#define REG_TX_OFDM_BBON		0x0e80
+#define REG_TX_TO_RX			0x0e84
+#define REG_TX_TO_TX			0x0e88
+#define REG_RX_CCK			0x0e8c
+
+#define REG_TX_POWER_BEFORE_IQK_A	0x0e94
+#define REG_TX_POWER_AFTER_IQK_A	0x0e9c
+
+#define REG_RX_POWER_BEFORE_IQK_A	0x0ea0
+#define REG_RX_POWER_BEFORE_IQK_A_2	0x0ea4
+#define REG_RX_POWER_AFTER_IQK_A	0x0ea8
+#define REG_RX_POWER_AFTER_IQK_A_2	0x0eac
+
+#define REG_TX_POWER_BEFORE_IQK_B	0x0eb4
+#define REG_TX_POWER_AFTER_IQK_B	0x0ebc
+
+#define REG_RX_POWER_BEFORE_IQK_B	0x0ec0
+#define REG_RX_POWER_BEFORE_IQK_B_2	0x0ec4
+#define REG_RX_POWER_AFTER_IQK_B	0x0ec8
+#define REG_RX_POWER_AFTER_IQK_B_2	0x0ecc
+
+#define REG_RX_OFDM			0x0ed0
+#define REG_RX_WAIT_RIFS		0x0ed4
+#define REG_RX_TO_RX			0x0ed8
+#define REG_STANDBY			0x0edc
+#define REG_SLEEP			0x0ee0
+#define REG_PMPD_ANAEN			0x0eec
+
+#define REG_FW_START_ADDRESS		0x1000
+
+#define REG_USB_INFO			0xfe17
+#define REG_USB_HIMR			0xfe38
+#define  USB_HIMR_TIMEOUT2		BIT(31)
+#define  USB_HIMR_TIMEOUT1		BIT(30)
+#define  USB_HIMR_PSTIMEOUT		BIT(29)
+#define  USB_HIMR_GTINT4		BIT(28)
+#define  USB_HIMR_GTINT3		BIT(27)
+#define  USB_HIMR_TXBCNERR		BIT(26)
+#define  USB_HIMR_TXBCNOK		BIT(25)
+#define  USB_HIMR_TSF_BIT32_TOGGLE	BIT(24)
+#define  USB_HIMR_BCNDMAINT3		BIT(23)
+#define  USB_HIMR_BCNDMAINT2		BIT(22)
+#define  USB_HIMR_BCNDMAINT1		BIT(21)
+#define  USB_HIMR_BCNDMAINT0		BIT(20)
+#define  USB_HIMR_BCNDOK3		BIT(19)
+#define  USB_HIMR_BCNDOK2		BIT(18)
+#define  USB_HIMR_BCNDOK1		BIT(17)
+#define  USB_HIMR_BCNDOK0		BIT(16)
+#define  USB_HIMR_HSISR_IND		BIT(15)
+#define  USB_HIMR_BCNDMAINT_E		BIT(14)
+/* RSVD	BIT(13) */
+#define  USB_HIMR_CTW_END		BIT(12)
+/* RSVD	BIT(11) */
+#define  USB_HIMR_C2HCMD		BIT(10)
+#define  USB_HIMR_CPWM2			BIT(9)
+#define  USB_HIMR_CPWM			BIT(8)
+#define  USB_HIMR_HIGHDOK		BIT(7)	/*  High Queue DMA OK
+						    Interrupt */
+#define  USB_HIMR_MGNTDOK		BIT(6)	/*  Management Queue DMA OK
+						    Interrupt */
+#define  USB_HIMR_BKDOK			BIT(5)	/*  AC_BK DMA OK Interrupt */
+#define  USB_HIMR_BEDOK			BIT(4)	/*  AC_BE DMA OK Interrupt */
+#define  USB_HIMR_VIDOK			BIT(3)	/*  AC_VI DMA OK Interrupt */
+#define  USB_HIMR_VODOK			BIT(2)	/*  AC_VO DMA Interrupt */
+#define  USB_HIMR_RDU			BIT(1)	/*  Receive Descriptor
+						    Unavailable */
+#define  USB_HIMR_ROK			BIT(0)	/*  Receive DMA OK Interrupt */
+
+#define REG_USB_SPECIAL_OPTION		0xfe55
+#define REG_USB_DMA_AGG_TO		0xfe5b
+#define REG_USB_AGG_TO			0xfe5c
+#define REG_USB_AGG_TH			0xfe5d
+
+#define REG_NORMAL_SIE_VID		0xfe60	/* 0xfe60 - 0xfe61 */
+#define REG_NORMAL_SIE_PID		0xfe62	/* 0xfe62 - 0xfe63 */
+#define REG_NORMAL_SIE_OPTIONAL		0xfe64
+#define REG_NORMAL_SIE_EP		0xfe65	/* 0xfe65 - 0xfe67 */
+#define REG_NORMAL_SIE_EP_TX		0xfe66
+#define  NORMAL_SIE_EP_TX_HIGH_MASK	0x000f
+#define  NORMAL_SIE_EP_TX_NORMAL_MASK	0x00f0
+#define  NORMAL_SIE_EP_TX_LOW_MASK	0x0f00
+
+#define REG_NORMAL_SIE_PHY		0xfe68	/* 0xfe68 - 0xfe6b */
+#define REG_NORMAL_SIE_OPTIONAL2	0xfe6c
+#define REG_NORMAL_SIE_GPS_EP		0xfe6d	/* RTL8723 only */
+#define REG_NORMAL_SIE_MAC_ADDR		0xfe70	/* 0xfe70 - 0xfe75 */
+#define REG_NORMAL_SIE_STRING		0xfe80	/* 0xfe80 - 0xfedf */
+
+/* RF6052 registers */
+#define RF6052_REG_AC			0x00
+#define RF6052_REG_IQADJ_G1		0x01
+#define RF6052_REG_IQADJ_G2		0x02
+#define RF6052_REG_BS_PA_APSET_G1_G4	0x03
+#define RF6052_REG_BS_PA_APSET_G5_G8	0x04
+#define RF6052_REG_POW_TRSW		0x05
+#define RF6052_REG_GAIN_RX		0x06
+#define RF6052_REG_GAIN_TX		0x07
+#define RF6052_REG_TXM_IDAC		0x08
+#define RF6052_REG_IPA_G		0x09
+#define RF6052_REG_TXBIAS_G		0x0a
+#define RF6052_REG_TXPA_AG		0x0b
+#define RF6052_REG_IPA_A		0x0c
+#define RF6052_REG_TXBIAS_A		0x0d
+#define RF6052_REG_BS_PA_APSET_G9_G11	0x0e
+#define RF6052_REG_BS_IQGEN		0x0f
+#define RF6052_REG_MODE1		0x10
+#define RF6052_REG_MODE2		0x11
+#define RF6052_REG_RX_AGC_HP		0x12
+#define RF6052_REG_TX_AGC		0x13
+#define RF6052_REG_BIAS			0x14
+#define RF6052_REG_IPA			0x15
+#define RF6052_REG_TXBIAS		0x16
+#define RF6052_REG_POW_ABILITY		0x17
+#define RF6052_REG_MODE_AG		0x18	/* RF channel and BW switch */
+#define  MODE_AG_CHANNEL_MASK		0x3ff
+#define  MODE_AG_CHANNEL_20MHZ		BIT(10)
+
+#define RF6052_REG_TOP			0x19
+#define RF6052_REG_RX_G1		0x1a
+#define RF6052_REG_RX_G2		0x1b
+#define RF6052_REG_RX_BB2		0x1c
+#define RF6052_REG_RX_BB1		0x1d
+#define RF6052_REG_RCK1			0x1e
+#define RF6052_REG_RCK2			0x1f
+#define RF6052_REG_TX_G1		0x20
+#define RF6052_REG_TX_G2		0x21
+#define RF6052_REG_TX_G3		0x22
+#define RF6052_REG_TX_BB1		0x23
+#define RF6052_REG_T_METER		0x24
+#define RF6052_REG_SYN_G1		0x25	/* RF TX Power control */
+#define RF6052_REG_SYN_G2		0x26	/* RF TX Power control */
+#define RF6052_REG_SYN_G3		0x27	/* RF TX Power control */
+#define RF6052_REG_SYN_G4		0x28	/* RF TX Power control */
+#define RF6052_REG_SYN_G5		0x29	/* RF TX Power control */
+#define RF6052_REG_SYN_G6		0x2a	/* RF TX Power control */
+#define RF6052_REG_SYN_G7		0x2b	/* RF TX Power control */
+#define RF6052_REG_SYN_G8		0x2c	/* RF TX Power control */
+
+#define RF6052_REG_RCK_OS		0x30	/* RF TX PA control */
+
+#define RF6052_REG_TXPA_G1		0x31	/* RF TX PA control */
+#define RF6052_REG_TXPA_G2		0x32	/* RF TX PA control */
+#define RF6052_REG_TXPA_G3		0x33	/* RF TX PA control */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 18:41     ` Jes Sorensen
  2015-08-30 21:02       ` Jes Sorensen
@ 2015-08-30 23:51       ` Larry Finger
  2015-08-31  2:39         ` Jes Sorensen
  2015-08-31  1:06       ` Joe Perches
  2015-08-31  8:19       ` Johannes Berg
  3 siblings, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-08-30 23:51 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, johannes

On 08/30/2015 01:41 PM, Jes Sorensen wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>> On 08/29/2015 04:18 PM, Jes.Sorensen@redhat.com wrote:
>>> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>>>
>>> This is an alternate driver for a number of Realtek WiFi USB devices,
>>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>>> It was written from scratch utilizing the Linux mac80211 stack.
>>>
>>> After spending months cleaning up the vendor provided rtl8723au
>>> driver, which comes with it's own 802.11 stack included, I decided to
>>> rewrite this driver from the bottom up.
>>>
>>> Many thanks to Johannes Berg for 802.11 insights and help and Larry
>>> Finger for help with the vendor driver.
>>>
>>> The full git log for the development of this driver can be found here:
>>> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>>>       branch rtl8723au-mac80211
>>>
>>> This driver is still under development, but has proven to be very
>>> stable for me. It currently supports station mode only. It has support
>>> for OFDM and CCK rates, as well as AMPDU. It does lack certain
>>> features found in the staging driver, such as power management and
>>> 40MHz channel support. In addition it does not support AD-HOC, AP, and
>>> monitor mode support at this point.
>>>
>>> The driver is known to work with the following devices:
>>> Lenovo Yoga (rtl8723au)
>>> TP-Link TL-WN823N (rtl8192cu)
>>> Etekcity 6R (rtl8188cu)
>>> Daffodil LAN03 (rtl8188cu)
>>> Alfa AWUS036NHR (rtl8188ru)
>>>
>>> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
>>
>> I did not realize you were resubmitting this driver so soon. I have
>> been accumulating some patches that I was going to send to you in the
>> next couple of days. The most important of these are described inline
>> below.
>
> Thanks - I already ran it through checkpatch, there is nothing from
> checkpatch that needs to be resolved.
>
>>> +
>>> +static int rtl8xxxu_debug = 0;
>>
>> Checkpatch reports:
>>
>> ERROR: do not initialise statics to 0 or NULL
>> #106: FILE: drivers/net/wireless/rtl8xxxu.c:45:
>> +static int rtl8xxxu_debug = 0;
>
> I really hate these pointless checkpatch warnings, but I guess I should
> just post the 0 in comments to not have to waste time on people
> submitting patches for this.
>
>>> +	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02lx bytes):\n",
>>> +		 __func__, sizeof(struct rtl8192cu_efuse));
>>
>> On a 32-bit PowerPC, the above line outputs the following:
>>
>> warning: format ‘%lx’ expects argument of type ‘long unsigned int’,
>> but argument 4 has type ‘unsigned int’ [-Wformat]
>>
>> This issue does not affect the object code, but it should be
>> fixed. Setting the format specifier to %02x and adding a cast of (int)
>> before the "size_of" will fix it on both sets of systems.
>
> Ewww, I didn't realize PowerPC 32 was this ugly :( Adding (long) as a
> cast would have the same effect here, but we will end up with an ugly
> cast in either case.
>
>>> +static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
>>> +{
>>> +	u32 val32;
>>> +	u32 rf_amode, rf_bmode = 0, lstf;
>>> +
>>> +	/* Check continuous TX and Packet TX */
>>> +	lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
>>> +
>>> +	if (lstf & OFDM_LSTF_MASK) {
>>> +		/* Disable all continuous TX */
>>> +		val32 = lstf & ~OFDM_LSTF_MASK;
>>> +		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
>>> +
>>> +		/* Read original RF mode Path A */
>>> +		rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC);
>>
>> The compiler on the PPC system (V4.6.3) is not as good at determining
>> if a variable has been set as is V4.8.3. It generates the warning
>> "warning: ‘rf_amode’ may be used uninitialized in this function
>> [-Wuninitialized]" for the above statement. As I hate to initialize
>> any variable that does not need it, this one should probably be left
>> alone; however, you may wish to add a comment.
>
> A comment would suffice, but the question is really whether it adds
> value to the code doing so - since 99.99% of users will never see this
> compiler warning. I am not opposed to zero initializing it, as I had to
> do the same with rf_bmode.
>
>>> +static void rtl8xxxu_tx(struct ieee80211_hw *hw,
>>> +			struct ieee80211_tx_control *control,
>>> +			struct sk_buff *skb)
>>> +{
>>> +	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
>>> +	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
>>> +	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
>>> +	struct rtl8xxxu_priv *priv = hw->priv;
>>> +	struct rtl8xxxu_tx_desc *tx_desc;
>>> +	struct ieee80211_sta *sta = NULL;
>>> +	struct rtl8xxxu_sta_priv *sta_priv = NULL;
>>> +	struct device *dev = &priv->udev->dev;
>>> +	struct urb *urb;
>>> +	u32 queue, rate;
>>> +	u16 pktlen = skb->len;
>>> +	u16 seq_number;
>>> +	u16 rate_flag = tx_info->control.rates[0].flags;
>>> +	int ret;
>>> +
>>> +	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
>>> +		dev_warn(dev,
>>> +			 "%s: Not enough headroom (%i) for tx descriptor\n",
>>> +			 __func__, skb_headroom(skb));
>>> +		goto error;
>>> +	}
>>> +
>>> +	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
>>> +		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
>>> +			 __func__, skb->len);
>>> +		goto error;
>>> +	}
>>> +
>>> +	urb = usb_alloc_urb(0, GFP_KERNEL);
>>
>> The above statement generated a "scheduling while atomic" splat. The
>> gfp_t argument needs to be GFP_KERNEL.
>
> You are seeing scheduling while atomic in the TX path? That just seems
> wrong to me - Johannes is the mac80211 TX path not meant to allow
> sleeping?
>
> I have never seen this on x86 and I have been running the driver for a
> long time. It is puzzling this causes a problem on PowerPC. It there
> something special in the config for it? I am inclined to say there is
> something wrong with the PPC32 setup rather than with my usage of
> GFP_KERNEL in the TX path.

The scheduling while atomic problem is on x86_64, not on PPC. I have lots of 
debugging/testing turned on in my configuration, but I cannot really identify 
which one might turn on the message. My config uses SLUB memory allocation, but 
that shouldn't matter either.

>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>> 0xff, 0xff),
>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>
>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>
> Were you happy with the results, or did it cause problems? Ie. did you
> try on x86 or on PPC32?

As covered in the other mail, it works very well at G rates.

>> Some comments that are not part of the review, but may be of interest
>> to potential users:
>>
>> 1. The gain settings on the RTL81{88,92}CU parts greatly reduce its
>> usefullnes. My Edimax 7811 can only find 1 of my 5 local APs in a
>> scan. It can connect to that AP, but achieves less than 10 Mbps for
>> both RX and TX operations. I expect to be able to discover better
>> initialization variables, but that may take a while.
>
> Interesting, I am trying to use the settings coming out of the efuse,
> but it is not impossible I do something wrong with them. So far I got
> decent results with 8192cu devices, But my testing with those has been
> limited.
>
>> 2. The driver fails to produce a wireless device on the PowerPC
>> because the firmware ready to run bit is never set. I have not seen
>> any reason for this to be a big-endian issue, and it may be another
>> pecularity of the USB subsystem on that laptop. For example, USB
>> devices that are plugged in at boot time fail, even though they work
>> if hot plugged into a running system.
>>
>> For a new driver written from scratch, it looks pretty good.
>
> Thanks for the comments, much appreciated!
>
> I don't think any of this is showstopper material for inclusion right
> now, albeit I do want to address them.

The scheduling while atomic problems do need to be fixed, and I am still working 
on the failure to get a wifi device on PPC.

Larry


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 18:41     ` Jes Sorensen
  2015-08-30 21:02       ` Jes Sorensen
  2015-08-30 23:51       ` Larry Finger
@ 2015-08-31  1:06       ` Joe Perches
  2015-08-31 13:11         ` Jes Sorensen
  2015-08-31  8:19       ` Johannes Berg
  3 siblings, 1 reply; 68+ messages in thread
From: Joe Perches @ 2015-08-31  1:06 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Larry Finger, linux-wireless, kvalo, johannes

On Sun, 2015-08-30 at 14:41 -0400, Jes Sorensen wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
[]
> >> +	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02lx bytes):\n",
> >> +		 __func__, sizeof(struct rtl8192cu_efuse));
> >
> > On a 32-bit PowerPC, the above line outputs the following:
> >
> > warning: format ‘%lx’ expects argument of type ‘long unsigned int’,
> > but argument 4 has type ‘unsigned int’ [-Wformat]
> >
> > This issue does not affect the object code, but it should be
> > fixed. Setting the format specifier to %02x and adding a cast of (int)
> > before the "size_of" will fix it on both sets of systems.
> 
> Ewww, I didn't realize PowerPC 32 was this ugly :( Adding (long) as a
> cast would have the same effect here, but we will end up with an ugly
> cast in either case.

don't cast at all and use format specifier %zu instead



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 23:51       ` Larry Finger
@ 2015-08-31  2:39         ` Jes Sorensen
  2015-08-31 15:45           ` Larry Finger
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-08-31  2:39 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, kvalo, johannes

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 08/30/2015 01:41 PM, Jes Sorensen wrote:
>>> The above statement generated a "scheduling while atomic" splat. The
>>> gfp_t argument needs to be GFP_KERNEL.
>>
>> You are seeing scheduling while atomic in the TX path? That just seems
>> wrong to me - Johannes is the mac80211 TX path not meant to allow
>> sleeping?
>>
>> I have never seen this on x86 and I have been running the driver for a
>> long time. It is puzzling this causes a problem on PowerPC. It there
>> something special in the config for it? I am inclined to say there is
>> something wrong with the PPC32 setup rather than with my usage of
>> GFP_KERNEL in the TX path.
>
> The scheduling while atomic problem is on x86_64, not on PPC. I have
> lots of debugging/testing turned on in my configuration, but I cannot
> really identify which one might turn on the message. My config uses
> SLUB memory allocation, but that shouldn't matter either.

I had some problems with mail delivery, so you may receive another
answer later - I checked up on it, and it was indeed a bug. You can
check my git branch for a version that won't suffer from this.

>>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>>> 0xff, 0xff),
>>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>>
>>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>>
>> Were you happy with the results, or did it cause problems? Ie. did you
>> try on x86 or on PPC32?
>
> As covered in the other mail, it works very well at G rates.

I see - I am a little confused, it works well on G rates but not on N
rates, or was this due to the AP used?

>> I don't think any of this is showstopper material for inclusion right
>> now, albeit I do want to address them.
>
> The scheduling while atomic problems do need to be fixed, and I am
> still working on the failure to get a wifi device on PPC.

It's already fixed :)

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 18:41     ` Jes Sorensen
                         ` (2 preceding siblings ...)
  2015-08-31  1:06       ` Joe Perches
@ 2015-08-31  8:19       ` Johannes Berg
  3 siblings, 0 replies; 68+ messages in thread
From: Johannes Berg @ 2015-08-31  8:19 UTC (permalink / raw)
  To: Jes Sorensen, Larry Finger; +Cc: linux-wireless, kvalo

On Sun, 2015-08-30 at 14:41 -0400, Jes Sorensen wrote:
> 
> > > +> > > 	> > > urb = usb_alloc_urb(0, GFP_KERNEL);
> > 
> > The above statement generated a "scheduling while atomic" splat. The
> > gfp_t argument needs to be GFP_KERNEL.
> 
> You are seeing scheduling while atomic in the TX path? That just seems
> wrong to me - Johannes is the mac80211 TX path not meant to allow
> sleeping?

The TX path is one of the few things where you can't sleep - that's
needed for performance reasons since the network stack doesn't allow
sleeping in the TX path.

> I have never seen this on x86 and I have been running the driver for a
> long time. It is puzzling this causes a problem on PowerPC. It there
> something special in the config for it? I am inclined to say there is
> something wrong with the PPC32 setup rather than with my usage of
> GFP_KERNEL in the TX path.

No, using GFP_KERNEL is wrong here. You're perhaps not enabling enough
options for it to come to a warning on x86.

> johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-31  1:06       ` Joe Perches
@ 2015-08-31 13:11         ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-08-31 13:11 UTC (permalink / raw)
  To: Joe Perches; +Cc: Larry Finger, linux-wireless, kvalo, johannes

Joe Perches <joe@perches.com> writes:
> On Sun, 2015-08-30 at 14:41 -0400, Jes Sorensen wrote:
>> Larry Finger <Larry.Finger@lwfinger.net> writes:
> []
>> >> +	dev_info(&priv->udev->dev, "%s: dumping efuse (0x%02lx bytes):\n",
>> >> +		 __func__, sizeof(struct rtl8192cu_efuse));
>> >
>> > On a 32-bit PowerPC, the above line outputs the following:
>> >
>> > warning: format ‘%lx’ expects argument of type ‘long unsigned int’,
>> > but argument 4 has type ‘unsigned int’ [-Wformat]
>> >
>> > This issue does not affect the object code, but it should be
>> > fixed. Setting the format specifier to %02x and adding a cast of (int)
>> > before the "size_of" will fix it on both sets of systems.
>> 
>> Ewww, I didn't realize PowerPC 32 was this ugly :( Adding (long) as a
>> cast would have the same effect here, but we will end up with an ugly
>> cast in either case.
>
> don't cast at all and use format specifier %zu instead

Would be %zx in this case, but thanks, I updated that.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-29 21:18 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
  2015-08-30  4:42   ` Larry Finger
@ 2015-08-31 14:48   ` Johannes Berg
  2015-08-31 23:42     ` Jes Sorensen
  2015-10-08 16:23   ` Jakub Sitnicki
  2 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-08-31 14:48 UTC (permalink / raw)
  To: Jes.Sorensen, linux-wireless; +Cc: kvalo, Larry.Finger

> + * This driver was written as a replacement for the vendor provided
> + * rtl8723au driver. As the Realtek 8xxx chips are very similar in
> + * their programming interface, I have started adding support for
> + * additional 8xxx chips like the 8192cu, 8188cus, etc.

That last sentence here seems like it might be more suitable in the
commit message then here - you'll surely forget to update it ;)

> +> 	> /*
> +> 	>  * MBOX ready?
> +> 	>  */
> +> 	> retry = 100;
> +> 	> do {
> +> 	> 	> val8 = rtl8xxxu_read8(priv, REG_HMTFR);
> +> 	> 	> if (!(val8 & BIT(mbox_nr)))
> +> 	> 	> 	> break;
> +> 	> } while (retry--);

Seems fishy without any delay in the loop?

> +> 	> val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
> +> 	> val32 &= ~OFDM_RF_PATH_TX_MASK;
> +> 	> if (priv->tx_paths == 2)


"TX path" is very uncommon language for this... I'd suggest changing
all that to "TX stream" or "TX chain"?

> +> 	> if (priv->rf_paths == 2)

Similar here - and should that be RX not RF?

> +static int rtl8723a_channel_to_group(int channel)
> +{
> +> 	> int group;
> +
> +> 	> if (channel < 4)
> +> 	> 	> group = 0;
> +> 	> else if (channel < 10)
> +> 	> 	> group = 1;
> +> 	> else
> +> 	> 	> group = 2;
> +
> +> 	> return group;
> +}

Could remove the group variable, it's kinda pointless - just return
immediately?

if (channel < 4)
	return 0;
if (channel < 10)
	return 1;
return 2;


> +> 	> /* Poll for data read */
> +> 	> val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
> +> 	> for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) {
> +> 	> 	> val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
> +> 	> 	> if (val32 & BIT(31))
> +> 	> 	> 	> break;
> +> 	> }
> 

Hmm, similar poll loop like above w/o any delay?
A few more seem to exist too.

> +> 	> 	> 	> for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
> +> 	> 	> 	> 	> /* Check word enable condition in the section */
> +> 	> 	> 	> 	> if (!(word_mask & BIT(i))) {
> +> 	> 	> 	> 	> 	> ret = rtl8xxxu_read_efuse8(priv,
> +> 	> 	> 	> 	> 	> 	> 	> 	>    efuse_addr++,
> +> 	> 	> 	> 	> 	> 	> 	> 	>    &val8);
> +> 	> 	> 	> 	> 	> if (ret)
> +> 	> 	> 	> 	> 	> 	> goto exit;
> +> 	> 	> 	> 	> 	> priv->efuse_wifi.raw[map_addr++] = val8;
> +
> +> 	> 	> 	> 	> 	> ret = rtl8xxxu_read_efuse8(priv,
> +> 	> 	> 	> 	> 	> 	> 	> 	>    efuse_addr++,
> +> 	> 	> 	> 	> 	> 	> 	> 	>    &val8);
> +> 	> 	> 	> 	> 	> if (ret)
> +> 	> 	> 	> 	> 	> 	> goto exit;
> +> 	> 	> 	> 	> 	> priv->efuse_wifi.raw[map_addr++] = val8;
> +> 	> 	> 	> 	> } else
> +> 	> 	> 	> 	> 	> map_addr += 2;
> +> 	> 	> 	> }

seems like it might better be in a helper function :)

> +static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
> +> 	> 	> 	> 	>   struct rtl8xxxu_reg32val *array)
> +{
> +> 	> int i, ret;
> +> 	> u16 reg;
> +> 	> u32 val;
> +
> +> 	> for (i = 0; ; i++) {
> +> 	> 	> reg = array[i].reg;
> +> 	> 	> val = array[i].val;
> +
> +> 	> 	> if (reg == 0xffff && val == 0xffffffff)
> +> 	> 	> 	> break;


Maybe passing ARRAY_SIZE to these would be nicer than having to they're
terminated? Dunno though, might be a lot of infrastructure to do that.

Ugh, getting too long for me - anything in particular I should look at?
:)

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-31  2:39         ` Jes Sorensen
@ 2015-08-31 15:45           ` Larry Finger
  2015-08-31 23:43             ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-08-31 15:45 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, johannes

On 08/30/2015 09:39 PM, Jes Sorensen wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>> On 08/30/2015 01:41 PM, Jes Sorensen wrote:
>>>> The above statement generated a "scheduling while atomic" splat. The
>>>> gfp_t argument needs to be GFP_KERNEL.
>>>
>>> You are seeing scheduling while atomic in the TX path? That just seems
>>> wrong to me - Johannes is the mac80211 TX path not meant to allow
>>> sleeping?
>>>
>>> I have never seen this on x86 and I have been running the driver for a
>>> long time. It is puzzling this causes a problem on PowerPC. It there
>>> something special in the config for it? I am inclined to say there is
>>> something wrong with the PPC32 setup rather than with my usage of
>>> GFP_KERNEL in the TX path.
>>
>> The scheduling while atomic problem is on x86_64, not on PPC. I have
>> lots of debugging/testing turned on in my configuration, but I cannot
>> really identify which one might turn on the message. My config uses
>> SLUB memory allocation, but that shouldn't matter either.
>
> I had some problems with mail delivery, so you may receive another
> answer later - I checked up on it, and it was indeed a bug. You can
> check my git branch for a version that won't suffer from this.
>
>>>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>>>> 0xff, 0xff),
>>>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>>>
>>>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>>>
>>> Were you happy with the results, or did it cause problems? Ie. did you
>>> try on x86 or on PPC32?
>>
>> As covered in the other mail, it works very well at G rates.
>
> I see - I am a little confused, it works well on G rates but not on N
> rates, or was this due to the AP used?

The AP is AC1200. It supports full N rates on other devices.
>
>>> I don't think any of this is showstopper material for inclusion right
>>> now, albeit I do want to address them.
>>
>> The scheduling while atomic problems do need to be fixed, and I am
>> still working on the failure to get a wifi device on PPC.
>
> It's already fixed :)

A full debug=0x3fff showed me one problem on the PPC. I will be testing a patch 
later today.

Larry



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-31 14:48   ` Johannes Berg
@ 2015-08-31 23:42     ` Jes Sorensen
  2015-09-01 15:07       ` Johannes Berg
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-08-31 23:42 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
>> + * This driver was written as a replacement for the vendor provided
>> + * rtl8723au driver. As the Realtek 8xxx chips are very similar in
>> + * their programming interface, I have started adding support for
>> + * additional 8xxx chips like the 8192cu, 8188cus, etc.
>
> That last sentence here seems like it might be more suitable in the
> commit message then here - you'll surely forget to update it ;)
>
>> +> 	> /*
>> +> 	>  * MBOX ready?
>> +> 	>  */
>> +> 	> retry = 100;
>> +> 	> do {
>> +> 	> 	> val8 = rtl8xxxu_read8(priv, REG_HMTFR);
>> +> 	> 	> if (!(val8 & BIT(mbox_nr)))
>> +> 	> 	> 	> break;
>> +> 	> } while (retry--);
>
> Seems fishy without any delay in the loop?

The access to USB registers introduces a delay automatically.

>> +> 	> val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
>> +> 	> val32 &= ~OFDM_RF_PATH_TX_MASK;
>> +> 	> if (priv->tx_paths == 2)
>
> "TX path" is very uncommon language for this... I'd suggest changing
> all that to "TX stream" or "TX chain"?
>
>> +> 	> if (priv->rf_paths == 2)
>
> Similar here - and should that be RX not RF?

I stuck with the naming from the vendor driver. The chip has antennas
and internal paths or streams and if I understand it right, granted not
having any specs whatsoever, I may have gotten some of it wrong, you can
wire path B to antenna A and vice versa. So it may only have one antenna
but uses path B to communicate.

>> +static int rtl8723a_channel_to_group(int channel)
>> +{
>> +> 	> int group;
>> +
>> +> 	> if (channel < 4)
>> +> 	> 	> group = 0;
>> +> 	> else if (channel < 10)
>> +> 	> 	> group = 1;
>> +> 	> else
>> +> 	> 	> group = 2;
>> +
>> +> 	> return group;
>> +}
>
> Could remove the group variable, it's kinda pointless - just return
> immediately?
>
> if (channel < 4)
> 	return 0;
> if (channel < 10)
> 	return 1;
> return 2;

I dislike returns in the middle of the function, but granted thats a
style preference.

>> +> 	> /* Poll for data read */
>> +> 	> val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
>> +> 	> for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) {
>> +> 	> 	> val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
>> +> 	> 	> if (val32 & BIT(31))
>> +> 	> 	> 	> break;
>> +> 	> }
>
> Hmm, similar poll loop like above w/o any delay?
> A few more seem to exist too.

For USB register reading, not having a delay should be fine, if we
looked at adding support for PCI, a delay is definitely needed.

>> +> 	> 	> 	> for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
>> +> > > > > /* Check word enable condition in the section */
>> +> 	> 	> 	> 	> if (!(word_mask & BIT(i))) {
>> +> 	> 	> 	> 	> 	> ret = rtl8xxxu_read_efuse8(priv,
>> +> > > > > > > > > efuse_addr++,
>> +> 	> 	> 	> 	> 	> 	> 	> 	>    &val8);
>> +> 	> 	> 	> 	> 	> if (ret)
>> +> 	> 	> 	> 	> 	> 	> goto exit;
>> +> > > > > > priv->efuse_wifi.raw[map_addr++] = val8;
>> +
>> +> 	> 	> 	> 	> 	> ret = rtl8xxxu_read_efuse8(priv,
>> +> > > > > > > > > efuse_addr++,
>> +> 	> 	> 	> 	> 	> 	> 	> 	>    &val8);
>> +> 	> 	> 	> 	> 	> if (ret)
>> +> 	> 	> 	> 	> 	> 	> goto exit;
>> +> > > > > > priv->efuse_wifi.raw[map_addr++] = val8;
>> +> 	> 	> 	> 	> } else
>> +> 	> 	> 	> 	> 	> map_addr += 2;
>> +> 	> 	> 	> }
>
> seems like it might better be in a helper function :)

Maybe :)

>> +static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
>> +> 	> 	> 	> 	>   struct rtl8xxxu_reg32val *array)
>> +{
>> +> 	> int i, ret;
>> +> 	> u16 reg;
>> +> 	> u32 val;
>> +
>> +> 	> for (i = 0; ; i++) {
>> +> 	> 	> reg = array[i].reg;
>> +> 	> 	> val = array[i].val;
>> +
>> +> 	> 	> if (reg == 0xffff && val == 0xffffffff)
>> +> 	> 	> 	> break;

> Maybe passing ARRAY_SIZE to these would be nicer than having to they're
> terminated? Dunno though, might be a lot of infrastructure to do that.

I prefer terminated arrays rather than calculating sizes, but it is also
a style issue.

> Ugh, getting too long for me - anything in particular I should look at?
> :)

Anything related to doing things correctly wrt to the mac80211 API would
be awesome.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-31 15:45           ` Larry Finger
@ 2015-08-31 23:43             ` Jes Sorensen
  2015-09-01  0:16               ` Larry Finger
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-08-31 23:43 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, kvalo, johannes

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 08/30/2015 09:39 PM, Jes Sorensen wrote:
>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>> On 08/30/2015 01:41 PM, Jes Sorensen wrote:
>>>>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>>>>> 0xff, 0xff),
>>>>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>>>>
>>>>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>>>>
>>>> Were you happy with the results, or did it cause problems? Ie. did you
>>>> try on x86 or on PPC32?
>>>
>>> As covered in the other mail, it works very well at G rates.
>>
>> I see - I am a little confused, it works well on G rates but not on N
>> rates, or was this due to the AP used?
>
> The AP is AC1200. It supports full N rates on other devices.

You only manage to make it work on G rates against this AP? Urgh, I
don't like that at all.

I thought you reported 30+Mbps performances though?, thats more than you
get on G.

>>>> I don't think any of this is showstopper material for inclusion right
>>>> now, albeit I do want to address them.
>>>
>>> The scheduling while atomic problems do need to be fixed, and I am
>>> still working on the failure to get a wifi device on PPC.
>>
>> It's already fixed :)
>
> A full debug=0x3fff showed me one problem on the PPC. I will be
> testing a patch later today.

Interesting, let me know what you find.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-31 23:43             ` Jes Sorensen
@ 2015-09-01  0:16               ` Larry Finger
  2015-09-01  4:54                 ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-09-01  0:16 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, johannes

[-- Attachment #1: Type: text/plain, Size: 2853 bytes --]

On 08/31/2015 06:43 PM, Jes Sorensen wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>> On 08/30/2015 09:39 PM, Jes Sorensen wrote:
>>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>>> On 08/30/2015 01:41 PM, Jes Sorensen wrote:
>>>>>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>>>>>> 0xff, 0xff),
>>>>>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>>>>>
>>>>>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>>>>>
>>>>> Were you happy with the results, or did it cause problems? Ie. did you
>>>>> try on x86 or on PPC32?
>>>>
>>>> As covered in the other mail, it works very well at G rates.
>>>
>>> I see - I am a little confused, it works well on G rates but not on N
>>> rates, or was this due to the AP used?
>>
>> The AP is AC1200. It supports full N rates on other devices.
>
> You only manage to make it work on G rates against this AP? Urgh, I
> don't like that at all.
>
> I thought you reported 30+Mbps performances though?, thats more than you
> get on G.

OK, I get a bit better than the top G rate of 27 Mbps, but the connection 
reports a 54 Mbps raw rate. My Intel 7260 gets RX of 95 and TX of 53 Mbps from 
the same location relative to the AP. For the Intel, the listed raw rate is 300 
Mbps.

>>>>> I don't think any of this is showstopper material for inclusion right
>>>>> now, albeit I do want to address them.
>>>>
>>>> The scheduling while atomic problems do need to be fixed, and I am
>>>> still working on the failure to get a wifi device on PPC.
>>>
>>> It's already fixed :)
>>
>> A full debug=0x3fff showed me one problem on the PPC. I will be
>> testing a patch later today.
>
> Interesting, let me know what you find.

Thanks for the fixes. I'm still getting the sleeping while atomic BUG splat from 
rtl8723a_h2c_cmd+0x48. Today I know that is not a lock dependency issue. I have 
one in VirtualBox that fires and disables further checking, but that driver is 
not loading now.

I have made some progress on the big-endian issues. When the firmware file is 
read from disk, the first byte read must be the first byte written to the 
device. In the slow write N routine, four bytes are picked and written using the 
write32 routine, which does a cpu_to_32() byte swap. As a result, the order of 
bytes to the device is 03, 02, 01, 00! Rather than byte swap twice, I am calling 
the regular writeN routine with each hunk. After a bit of thinking about the 
best blocksize to use, I settled on 64. That reduces the number of full-size 
hunks that are written without unduly increasing the worst-case number of writes 
needed for the remainder.

On PPC, I now get a device registered; however, the scan data are garbled. That 
shouldn't be too difficult to debug, but just in case, I have attached the patch 
for rtl8xxxu_slow_writeN().

Larry




[-- Attachment #2: fix_big_endian_fw_download.patch --]
[-- Type: text/x-patch, Size: 938 bytes --]

diff --git a/drivers/net/wireless/rtl8xxxu.c b/drivers/net/wireless/rtl8xxxu.c
index 8773884..80602b8 100644
--- a/drivers/net/wireless/rtl8xxxu.c
+++ b/drivers/net/wireless/rtl8xxxu.c
@@ -1099,17 +1099,18 @@ rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
 static int
 rtl8xxxu_slow_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
 {
-	u32 blocksize = sizeof(u32);
-	u32 *buf4 = (u32 *)buf;
+	u32 blocksize = 64;
 	int i, offset, count, remainder;
 
+	/* This routine does not do any btye swapping on big-endian machines.
+	 * It should be used for writing firmware, and nothing else */
 	count = len / blocksize;
 	remainder = len % blocksize;
 
 	for (i = 0; i < count; i++) {
 		offset = i * blocksize;
-		rtl8xxxu_write32(priv, (REG_FW_START_ADDRESS + offset),
-				 buf4[i]);
+		rtl8xxxu_writeN(priv, (REG_FW_START_ADDRESS + offset),
+				(buf + offset), blocksize);
 	}
 
 	if (remainder) {


^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-01  0:16               ` Larry Finger
@ 2015-09-01  4:54                 ` Jes Sorensen
  2015-09-01  5:17                   ` Larry Finger
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-09-01  4:54 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless, kvalo, johannes

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 08/31/2015 06:43 PM, Jes Sorensen wrote:
>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>> On 08/30/2015 09:39 PM, Jes Sorensen wrote:
>>>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>>>> On 08/30/2015 01:41 PM, Jes Sorensen wrote:
>>>>>>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>>>>>>> 0xff, 0xff),
>>>>>>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>>>>>>
>>>>>>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>>>>>>
>>>>>> Were you happy with the results, or did it cause problems? Ie. did you
>>>>>> try on x86 or on PPC32?
>>>>>
>>>>> As covered in the other mail, it works very well at G rates.
>>>>
>>>> I see - I am a little confused, it works well on G rates but not on N
>>>> rates, or was this due to the AP used?
>>>
>>> The AP is AC1200. It supports full N rates on other devices.
>>
>> You only manage to make it work on G rates against this AP? Urgh, I
>> don't like that at all.
>>
>> I thought you reported 30+Mbps performances though?, thats more than you
>> get on G.
>
> OK, I get a bit better than the top G rate of 27 Mbps, but the
> connection reports a 54 Mbps raw rate. My Intel 7260 gets RX of 95 and
> TX of 53 Mbps from the same location relative to the AP. For the
> Intel, the listed raw rate is 300 Mbps.

It's possible the connection reporting I am doing is wrong. I haven't
figured out how to report the actual transmission speed, which is what
the mac80211 stack wants. Some of the other drivers fake it or repor RX
speeds, but that isn't what one is meant to report.

>>> A full debug=0x3fff showed me one problem on the PPC. I will be
>>> testing a patch later today.
>>
>> Interesting, let me know what you find.
>
> Thanks for the fixes. I'm still getting the sleeping while atomic BUG
> splat from rtl8723a_h2c_cmd+0x48. Today I know that is not a lock
> dependency issue. I have one in VirtualBox that fires and disables
> further checking, but that driver is not loading now.

This is bothersome, I'll have to dig futher into this.

> I have made some progress on the big-endian issues. When the firmware
> file is read from disk, the first byte read must be the first byte
> written to the device. In the slow write N routine, four bytes are
> picked and written using the write32 routine, which does a cpu_to_32()
> byte swap. As a result, the order of bytes to the device is 03, 02,
> 01, 00! Rather than byte swap twice, I am calling the regular writeN
> routine with each hunk. After a bit of thinking about the best
> blocksize to use, I settled on 64. That reduces the number of
> full-size hunks that are written without unduly increasing the
> worst-case number of writes needed for the remainder.
>
> On PPC, I now get a device registered; however, the scan data are
> garbled. That shouldn't be too difficult to debug, but just in case, I
> have attached the patch for rtl8xxxu_slow_writeN().

As I mentioned in a direct email - calling writeN from slow_writeN is
not a solution. I found some devices fail if you try to use the fast
writeN routine. Maybe rtl8xxxu_raw_write32() - without the byteswap
would be a better approach, or simply putting the relevant code into the
slow_writeN function.

I am flying back to New York tomorrow, and I'll have some time on the
plane, so I'll try to have a look at that.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-01  4:54                 ` Jes Sorensen
@ 2015-09-01  5:17                   ` Larry Finger
  2015-09-01  5:26                     ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-09-01  5:17 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, johannes

On 08/31/2015 11:54 PM, Jes Sorensen wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>> On 08/31/2015 06:43 PM, Jes Sorensen wrote:
>>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>>> On 08/30/2015 09:39 PM, Jes Sorensen wrote:
>>>>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>>>>>> On 08/30/2015 01:41 PM, Jes Sorensen wrote:
>>>>>>>>> +{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff,
>>>>>>>> 0xff, 0xff),
>>>>>>>>> +	.driver_info = (unsigned long)&rtl8192cu_fops},
>>>>>>>>
>>>>>>>> I have tested a device with USB ID 0x0bda (USB_VENDOR_ID_REALTEK):0x817e.
>>>>>>>
>>>>>>> Were you happy with the results, or did it cause problems? Ie. did you
>>>>>>> try on x86 or on PPC32?
>>>>>>
>>>>>> As covered in the other mail, it works very well at G rates.
>>>>>
>>>>> I see - I am a little confused, it works well on G rates but not on N
>>>>> rates, or was this due to the AP used?
>>>>
>>>> The AP is AC1200. It supports full N rates on other devices.
>>>
>>> You only manage to make it work on G rates against this AP? Urgh, I
>>> don't like that at all.
>>>
>>> I thought you reported 30+Mbps performances though?, thats more than you
>>> get on G.
>>
>> OK, I get a bit better than the top G rate of 27 Mbps, but the
>> connection reports a 54 Mbps raw rate. My Intel 7260 gets RX of 95 and
>> TX of 53 Mbps from the same location relative to the AP. For the
>> Intel, the listed raw rate is 300 Mbps.
>
> It's possible the connection reporting I am doing is wrong. I haven't
> figured out how to report the actual transmission speed, which is what
> the mac80211 stack wants. Some of the other drivers fake it or repor RX
> speeds, but that isn't what one is meant to report.
>
>>>> A full debug=0x3fff showed me one problem on the PPC. I will be
>>>> testing a patch later today.
>>>
>>> Interesting, let me know what you find.
>>
>> Thanks for the fixes. I'm still getting the sleeping while atomic BUG
>> splat from rtl8723a_h2c_cmd+0x48. Today I know that is not a lock
>> dependency issue. I have one in VirtualBox that fires and disables
>> further checking, but that driver is not loading now.
>
> This is bothersome, I'll have to dig futher into this.
>
>> I have made some progress on the big-endian issues. When the firmware
>> file is read from disk, the first byte read must be the first byte
>> written to the device. In the slow write N routine, four bytes are
>> picked and written using the write32 routine, which does a cpu_to_32()
>> byte swap. As a result, the order of bytes to the device is 03, 02,
>> 01, 00! Rather than byte swap twice, I am calling the regular writeN
>> routine with each hunk. After a bit of thinking about the best
>> blocksize to use, I settled on 64. That reduces the number of
>> full-size hunks that are written without unduly increasing the
>> worst-case number of writes needed for the remainder.
>>
>> On PPC, I now get a device registered; however, the scan data are
>> garbled. That shouldn't be too difficult to debug, but just in case, I
>> have attached the patch for rtl8xxxu_slow_writeN().
>
> As I mentioned in a direct email - calling writeN from slow_writeN is
> not a solution. I found some devices fail if you try to use the fast
> writeN routine. Maybe rtl8xxxu_raw_write32() - without the byteswap
> would be a better approach, or simply putting the relevant code into the
> slow_writeN function.
>
> I am flying back to New York tomorrow, and I'll have some time on the
> plane, so I'll try to have a look at that.

I also found that trying to write all N bytes at once failed, but writing 64 at 
a time is OK. I will add the USB calls to slow_writeN.

Larry



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-01  5:17                   ` Larry Finger
@ 2015-09-01  5:26                     ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-01  5:26 UTC (permalink / raw)
  To: Larry Finger; +Cc: linux-wireless

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 08/31/2015 11:54 PM, Jes Sorensen wrote:
>> As I mentioned in a direct email - calling writeN from slow_writeN is
>> not a solution. I found some devices fail if you try to use the fast
>> writeN routine. Maybe rtl8xxxu_raw_write32() - without the byteswap
>> would be a better approach, or simply putting the relevant code into the
>> slow_writeN function.
>>
>> I am flying back to New York tomorrow, and I'll have some time on the
>> plane, so I'll try to have a look at that.
>
> I also found that trying to write all N bytes at once failed, but
> writing 64 at a time is OK. I will add the USB calls to slow_writeN.

I see, it's possible we need to add it as a parameter to writeN or add
the size to the fops struct for the different device types. In fact the
latter might be a cleaner approach, especially if it works for 8192/8188
devices with 64 byte writes. Getting rid of slow_writeN altogether would
be nice.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-31 23:42     ` Jes Sorensen
@ 2015-09-01 15:07       ` Johannes Berg
  2015-09-03  1:59         ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-09-01 15:07 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger

On Mon, 2015-08-31 at 19:42 -0400, Jes Sorensen wrote:
> 
> Anything related to doing things correctly wrt to the mac80211 API 
> would be awesome.

:)

> static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
>                                   struct ieee80211_vif *vif)
> {
>         struct rtl8xxxu_priv *priv = hw-&gt;priv;
>         int ret;
>         u8 val8;
> 
>         switch (vif-&gt;type) {    
>         case NL80211_IFTYPE_STATION:
>                 rtl8723a_stop_tx_beacon(priv);

This seems odd - you shouldn't have any kind of operation before
add_interface(), so why stop anything?
(You also don't even support beaconing yet anyway)

>                 /*
>                  * This is a bit of a hack - the lower bits of the cipher 
>                  * suite selector happens to match the cipher index in the
>                  * CAM
>                  */

That's probably simply intentional - the cipher suite selector is built
as a OUI : cipher number ...

However - I don't see any code actually using key->cipher here? You
should move the comment into rtl8xxxu_cam_write() I guess.

> static int
> rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>                       enum ieee80211_ampdu_mlme_action action,
>                       struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
> {
>         struct rtl8xxxu_priv *priv = hw->priv;
>         struct device *dev = &priv->udev->dev;
>         u8 ampdu_factor, ampdu_density;
> 
>         switch (action) {
[...]

I'd be extremely surprised if any of this worked - perhaps you're not
advertising A-MPDU support (yet)?

You're not calling ieee80211_start_tx_ba_cb_irqsafe() or
ieee80211_stop_tx_ba_cb_irqsafe(), so this can't really work. The
session might be set up but will never actually start.

That said, the code also looks incomplete. Perhaps better to just
remove it entirely for now?

>         sta_priv->short_preamble = false;

I don't think there's any need to track it, especially since you only
use it in TX where you have the TX info data about it.

> };

stray semicolons at the end of functions in a few places :)

I guess you can get rid of sta_add/remove entirely. sta_state() is the
better hook to implement, but you don't really need any of the three.

> static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
>                                    struct ieee80211_vif *vif, const u8 *mac)
> {
> }

No need for this ... You'll get stop even without the start, but
actually I think your start is perhaps missing setting
BEACON_DISABLE_TSF_UPDATE (which stop clears)

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-01 15:07       ` Johannes Berg
@ 2015-09-03  1:59         ` Jes Sorensen
  2015-09-03  2:39           ` Jes Sorensen
  2015-09-03 10:17           ` Johannes Berg
  0 siblings, 2 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-03  1:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Mon, 2015-08-31 at 19:42 -0400, Jes Sorensen wrote:
>> 
>> Anything related to doing things correctly wrt to the mac80211 API 
>> would be awesome.
>
> :)
>
>> static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
>>                                   struct ieee80211_vif *vif)
>> {
>>         struct rtl8xxxu_priv *priv = hw-&gt;priv;
>>         int ret;
>>         u8 val8;
>> 
>>         switch (vif-&gt;type) {    
>>         case NL80211_IFTYPE_STATION:
>>                 rtl8723a_stop_tx_beacon(priv);
>
> This seems odd - you shouldn't have any kind of operation before
> add_interface(), so why stop anything?
> (You also don't even support beaconing yet anyway)

The code mimics what the vendor driver does - part of the bringup of the
chip sets a bunch of parameters from an register value array. Rather
than guessing what their default is, I feel it's safer to just shut it
down here and stick with that.

>
>>                 /*
>>                  * This is a bit of a hack - the lower bits of the cipher 
>>                  * suite selector happens to match the cipher index in the
>>                  * CAM
>>                  */
>
> That's probably simply intentional - the cipher suite selector is built
> as a OUI : cipher number ...
>
> However - I don't see any code actually using key->cipher here? You
> should move the comment into rtl8xxxu_cam_write() I guess.

I did assume it was intentional, but still a bit of a hack in my book.
I'll move the comment, as you suggested.

>> static int
>> rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
>>                       enum ieee80211_ampdu_mlme_action action,
>>                       struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
>> {
>>         struct rtl8xxxu_priv *priv = hw->priv;
>>         struct device *dev = &priv->udev->dev;
>>         u8 ampdu_factor, ampdu_density;
>> 
>>         switch (action) {
> [...]
>
> I'd be extremely surprised if any of this worked - perhaps you're not
> advertising A-MPDU support (yet)?
>
> You're not calling ieee80211_start_tx_ba_cb_irqsafe() or
> ieee80211_stop_tx_ba_cb_irqsafe(), so this can't really work. The
> session might be set up but will never actually start.
>
> That said, the code also looks incomplete. Perhaps better to just
> remove it entirely for now?

I started working on this, but I guess I didn't finish it. One thing I
haven't figured out yet is why I see AMPDU_RX_START events, but I never
see AMPDU_TX_START events show in the log.

>>         sta_priv->short_preamble = false;
>
> I don't think there's any need to track it, especially since you only
> use it in TX where you have the TX info data about it.

Oh, I hadn't spotted that information in struct tx_info - in that case I
ought to be able to get rid of this one.

>
>> };
>
> stray semicolons at the end of functions in a few places :)

Gone :)

> I guess you can get rid of sta_add/remove entirely. sta_state() is the
> better hook to implement, but you don't really need any of the three.

I added it because I was looking at using it for AMPDU, then got stock,
but didn't feel like removing it in case I would need it later.

I need to figure out what goes on with the AMPDU side of things - the
problem writing a driver like this without any spec sheets is that it
isn't quite clear to me, how much of this the firmware takes care of
transparently.

>> static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
>>                                    struct ieee80211_vif *vif, const u8 *mac)
>> {
>> }
>
> No need for this ... You'll get stop even without the start, but
> actually I think your start is perhaps missing setting
> BEACON_DISABLE_TSF_UPDATE (which stop clears)

I'll have a look at this.

Thanks for the comments!

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-03  1:59         ` Jes Sorensen
@ 2015-09-03  2:39           ` Jes Sorensen
  2015-09-03 10:17             ` Johannes Berg
  2015-09-03 10:17           ` Johannes Berg
  1 sibling, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-09-03  2:39 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, kvalo, Larry.Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:
> Johannes Berg <johannes@sipsolutions.net> writes:
>>>         sta_priv->short_preamble = false;
>>
>> I don't think there's any need to track it, especially since you only
>> use it in TX where you have the TX info data about it.
>
> Oh, I hadn't spotted that information in struct tx_info - in that case I
> ought to be able to get rid of this one.

I went back and looked at this, and now I remember why I wrote the code
the way I did. The Realtek firmware handles rate control, so once I set
IEEE80211_HW_HAS_RATE_CONTROL, I never see
rate_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE nor
tx_info->control_short_preamble.  In order to know whether to tell the
firmware to request short preamble or not, I needed to track whether the
sta supports it.

Do you have a suggestion for how to handle this in a better way?

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-03  1:59         ` Jes Sorensen
  2015-09-03  2:39           ` Jes Sorensen
@ 2015-09-03 10:17           ` Johannes Berg
  2015-09-04 17:48             ` Jes Sorensen
  1 sibling, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-09-03 10:17 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger

On Wed, 2015-09-02 at 21:59 -0400, Jes Sorensen wrote:
> 
> The code mimics what the vendor driver does - part of the bringup of the
> chip sets a bunch of parameters from an register value array. Rather
> than guessing what their default is, I feel it's safer to just shut 
> it down here and stick with that.

Ok, fair enough. Might be worth putting that into start() rather than
add_interface() though? Anyway, it's not a big deal, I just wasn't sure
if that was intentional.

> > I'd be extremely surprised if any of this worked - perhaps you're 
> > not advertising A-MPDU support (yet)?
> > 
> > You're not calling ieee80211_start_tx_ba_cb_irqsafe() or
> > ieee80211_stop_tx_ba_cb_irqsafe(), so this can't really work. The
> > session might be set up but will never actually start.
> > 
> > That said, the code also looks incomplete. Perhaps better to just
> > remove it entirely for now?
> 
> I started working on this, but I guess I didn't finish it. One thing I
> haven't figured out yet is why I see AMPDU_RX_START events, but I never
> see AMPDU_TX_START events show in the log.

Nothing in your system is calling ieee80211_start_tx_ba_session() then.


johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-03  2:39           ` Jes Sorensen
@ 2015-09-03 10:17             ` Johannes Berg
  2015-09-04 18:24               ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-09-03 10:17 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger

On Wed, 2015-09-02 at 22:39 -0400, Jes Sorensen wrote:
> 
> I went back and looked at this, and now I remember why I wrote the code
> the way I did. The Realtek firmware handles rate control, so once I set
> IEEE80211_HW_HAS_RATE_CONTROL, I never see
> rate_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE nor
> tx_info->control_short_preamble.  In order to know whether to tell the
> firmware to request short preamble or not, I needed to track whether the
> sta supports it.
> 
> Do you have a suggestion for how to handle this in a better way?
> 

Ah, this makes sense. There's an rc_update call or something like that,
that might have the requisite information. Not really sure off the top
of my head.

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-03 10:17           ` Johannes Berg
@ 2015-09-04 17:48             ` Jes Sorensen
  2015-09-04 18:02               ` Johannes Berg
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-09-04 17:48 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Wed, 2015-09-02 at 21:59 -0400, Jes Sorensen wrote:
>> 
>> The code mimics what the vendor driver does - part of the bringup of the
>> chip sets a bunch of parameters from an register value array. Rather
>> than guessing what their default is, I feel it's safer to just shut 
>> it down here and stick with that.
>
> Ok, fair enough. Might be worth putting that into start() rather than
> add_interface() though? Anyway, it's not a big deal, I just wasn't sure
> if that was intentional.

OK, I'll probably just leave it there for now then.

>> > I'd be extremely surprised if any of this worked - perhaps you're 
>> > not advertising A-MPDU support (yet)?
>> > 
>> > You're not calling ieee80211_start_tx_ba_cb_irqsafe() or
>> > ieee80211_stop_tx_ba_cb_irqsafe(), so this can't really work. The
>> > session might be set up but will never actually start.
>> > 
>> > That said, the code also looks incomplete. Perhaps better to just
>> > remove it entirely for now?
>> 
>> I started working on this, but I guess I didn't finish it. One thing I
>> haven't figured out yet is why I see AMPDU_RX_START events, but I never
>> see AMPDU_TX_START events show in the log.
>
> Nothing in your system is calling ieee80211_start_tx_ba_session() then.

Gotcha, now you mention it, that rings a bell! I'll put that on my todo
list. One of the biggest things puzzling me is how much the firmware
does with AMPDU - there is a break bit I can set in the TX descriptor to
say 'don't AMPDU this packet' but do not actually know if it will do all
of this behind my back. I need to dig more into the vendor driver (and
their 80211 stack) to see if I can figure that out.

Cheers,
Jes



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-04 17:48             ` Jes Sorensen
@ 2015-09-04 18:02               ` Johannes Berg
  0 siblings, 0 replies; 68+ messages in thread
From: Johannes Berg @ 2015-09-04 18:02 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger

On Fri, 2015-09-04 at 13:48 -0400, Jes Sorensen wrote:
> 
> Gotcha, now you mention it, that rings a bell! I'll put that on my todo
> list. One of the biggest things puzzling me is how much the firmware
> does with AMPDU - there is a break bit I can set in the TX descriptor to
> say 'don't AMPDU this packet' but do not actually know if it will do all
> of this behind my back. I need to dig more into the vendor driver (and
> their 80211 stack) to see if I can figure that out.
> 

That also seems possibly like something you'd set within an existing
aggregation session - you can still send non-aggregated frames, and
might decide to do that for example for EAPOL frames.

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-03 10:17             ` Johannes Berg
@ 2015-09-04 18:24               ` Jes Sorensen
  2015-09-04 18:25                 ` Johannes Berg
  2015-09-05  4:02                 ` Sujith Manoharan
  0 siblings, 2 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-04 18:24 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Wed, 2015-09-02 at 22:39 -0400, Jes Sorensen wrote:
>> 
>> I went back and looked at this, and now I remember why I wrote the code
>> the way I did. The Realtek firmware handles rate control, so once I set
>> IEEE80211_HW_HAS_RATE_CONTROL, I never see
>> rate_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE nor
>> tx_info->control_short_preamble.  In order to know whether to tell the
>> firmware to request short preamble or not, I needed to track whether the
>> sta supports it.
>> 
>> Do you have a suggestion for how to handle this in a better way?
>> 
>
> Ah, this makes sense. There's an rc_update call or something like that,
> that might have the requisite information. Not really sure off the top
> of my head.

I'll add a comment to the code explaining why it is done this way. I had
a peak at the rate_control code earlier, but it wasn't obvious to me
whether I should be using that API at all. Is there an explanation of
the API and it's usage somewhere?

Cheers,
Jes



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-04 18:24               ` Jes Sorensen
@ 2015-09-04 18:25                 ` Johannes Berg
  2015-09-05  4:02                 ` Sujith Manoharan
  1 sibling, 0 replies; 68+ messages in thread
From: Johannes Berg @ 2015-09-04 18:25 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger


> I'll add a comment to the code explaining why it is done this way. I 
> had
> a peak at the rate_control code earlier, but it wasn't obvious to me
> whether I should be using that API at all. Is there an explanation of
> the API and it's usage somewhere?
> 

Sadly no, it's one of the oldest and in a way cruftiest parts of the
code, though it has seen a fair share of modernisation :)

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-04 18:24               ` Jes Sorensen
  2015-09-04 18:25                 ` Johannes Berg
@ 2015-09-05  4:02                 ` Sujith Manoharan
  2015-09-17 16:46                   ` Johannes Berg
  1 sibling, 1 reply; 68+ messages in thread
From: Sujith Manoharan @ 2015-09-05  4:02 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Johannes Berg, linux-wireless, kvalo, Larry.Finger

Jes Sorensen wrote:
> > Ah, this makes sense. There's an rc_update call or something like that,
> > that might have the requisite information. Not really sure off the top
> > of my head.

ieee80211_sta doesn't contain the preamble information, though ?

The bss information holds the short preamble information, so that can
probably be used - using BSS_CHANGED_ERP_PREAMBLE.

> I'll add a comment to the code explaining why it is done this way. I had
> a peak at the rate_control code earlier, but it wasn't obvious to me
> whether I should be using that API at all. Is there an explanation of
> the API and it's usage somewhere?

sta_rc_update() can be used when the target firmware (or a custom rate
control module) expects the driver to provide valid operational bitrates.

Sujith

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-08-30 21:02 [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
  2015-08-30 21:02 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
@ 2015-09-06 14:43 ` Kalle Valo
  2015-09-06 17:03   ` Larry Finger
  2015-09-07  1:45   ` Jes Sorensen
  1 sibling, 2 replies; 68+ messages in thread
From: Kalle Valo @ 2015-09-06 14:43 UTC (permalink / raw)
  To: Jes.Sorensen; +Cc: linux-wireless, Larry.Finger

Jes.Sorensen@redhat.com writes:

> Per default only devices I have actually tested will be enabled. If
> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
> test results back to me.
>
> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
> to which module you load and/or use modprobe blacklists.

May clash? So how does this work in practise? Is the clash referring
CONFIG_RTL8XXXU_UNTESTED enabled or disabled?

I think we should only have one driver automatically supporting certain
hardware, and not have a driver randomly chosen and forcing users to use
a blacklist.

Also how do we make sure that distros don't enable
CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
without thinking.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-30 21:02 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
@ 2015-09-06 14:59   ` Kalle Valo
  2015-09-06 17:06     ` Larry Finger
  2015-09-07  1:40     ` Jes Sorensen
  0 siblings, 2 replies; 68+ messages in thread
From: Kalle Valo @ 2015-09-06 14:59 UTC (permalink / raw)
  To: Jes.Sorensen; +Cc: linux-wireless, Larry.Finger

Jes.Sorensen@redhat.com writes:

> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>
> This is an alternate driver for a number of Realtek WiFi USB devices,
> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
> It was written from scratch utilizing the Linux mac80211 stack.
>
> After spending months cleaning up the vendor provided rtl8723au
> driver, which comes with it's own 802.11 stack included, I decided to
> rewrite this driver from the bottom up.
>
> Many thanks to Johannes Berg for 802.11 insights and help and Larry
> Finger for help with the vendor driver.
>
> The full git log for the development of this driver can be found here:
> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>     branch rtl8723au-mac80211
>
> This driver is still under development, but has proven to be very
> stable for me. It currently supports station mode only. It has support
> for OFDM and CCK rates, as well as AMPDU. It does lack certain
> features found in the staging driver, such as power management and
> 40MHz channel support. In addition it does not support AD-HOC, AP, and
> monitor mode support at this point.
>
> The driver is known to work with the following devices:
> Lenovo Yoga (rtl8723au)
> TP-Link TL-WN823N (rtl8192cu)
> Etekcity 6R (rtl8188cu)
> Daffodil LAN03 (rtl8188cu)
> Alfa AWUS036NHR (rtl8188ru)
>
> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>

You forgot v2 from the subject.

> v2: Contains fixes for problems reported by Larry Finger
> ---

Changelog should be under "---" line.

> +static int rtl8xxxu_debug /* = 0 */; /* Avoid pointless checkpatch noise */

Either assign it to zero or ignore the checkpatch warning, but please
don't do this.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-06 14:43 ` [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Kalle Valo
@ 2015-09-06 17:03   ` Larry Finger
  2015-09-07  9:06     ` Kalle Valo
  2015-09-08 21:01     ` Jes Sorensen
  2015-09-07  1:45   ` Jes Sorensen
  1 sibling, 2 replies; 68+ messages in thread
From: Larry Finger @ 2015-09-06 17:03 UTC (permalink / raw)
  To: Kalle Valo, Jes.Sorensen; +Cc: linux-wireless

On 09/06/2015 09:43 AM, Kalle Valo wrote:
> Jes.Sorensen@redhat.com writes:
>
>> Per default only devices I have actually tested will be enabled. If
>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>> test results back to me.
>>
>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>> to which module you load and/or use modprobe blacklists.
>
> May clash? So how does this work in practise? Is the clash referring
> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>
> I think we should only have one driver automatically supporting certain
> hardware, and not have a driver randomly chosen and forcing users to use
> a blacklist.

I agree, in principle, but there will be difficulties in the implementation, at 
least in the short term.

At the moment, the only driver that has a conflict with rtl8xxxu is rtl8192cu. 
Although rtl8xxxu is surprisingly more stable that rtl8192cu, the latter has 
more features, which is may be the reason for better stability. Driver rtl8xxxu 
does not handle any 40 MHz channels, nor can it become an AP either with hostapd 
or with NetworkManager. For those reasons, rtl819cu has to remain the standard 
driver for RTL81{88,92}CU devices until rtl8xxxu is improved. Anyone that wants 
to try the new driver will need to use blacklists.

We can make changes in the Kconfig help texts that clarify the situation, but 
that will not help the user of kernels built by the distros.

> Also how do we make sure that distros don't enable
> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
> without thinking.

It will not necessarily depend on whether CONFIG_RTL8XXXU_UNTESTED is enabled or 
not. Some of the affected devices are in the tested category.

Larry


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-06 14:59   ` Kalle Valo
@ 2015-09-06 17:06     ` Larry Finger
  2015-09-07  1:41       ` Jes Sorensen
  2015-09-07  1:40     ` Jes Sorensen
  1 sibling, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-09-06 17:06 UTC (permalink / raw)
  To: Kalle Valo, Jes.Sorensen; +Cc: linux-wireless

On 09/06/2015 09:59 AM, Kalle Valo wrote:
> Jes.Sorensen@redhat.com writes:
>
>> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>>
>> This is an alternate driver for a number of Realtek WiFi USB devices,
>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>> It was written from scratch utilizing the Linux mac80211 stack.
>>
>> After spending months cleaning up the vendor provided rtl8723au
>> driver, which comes with it's own 802.11 stack included, I decided to
>> rewrite this driver from the bottom up.
>>
>> Many thanks to Johannes Berg for 802.11 insights and help and Larry
>> Finger for help with the vendor driver.
>>
>> The full git log for the development of this driver can be found here:
>> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>>      branch rtl8723au-mac80211
>>
>> This driver is still under development, but has proven to be very
>> stable for me. It currently supports station mode only. It has support
>> for OFDM and CCK rates, as well as AMPDU. It does lack certain
>> features found in the staging driver, such as power management and
>> 40MHz channel support. In addition it does not support AD-HOC, AP, and
>> monitor mode support at this point.
>>
>> The driver is known to work with the following devices:
>> Lenovo Yoga (rtl8723au)
>> TP-Link TL-WN823N (rtl8192cu)
>> Etekcity 6R (rtl8188cu)
>> Daffodil LAN03 (rtl8188cu)
>> Alfa AWUS036NHR (rtl8188ru)

One other comment is that using lower case such as rtl8723au indicates a driver, 
whereas RTL8723AU is a device. There are no drivers rtl8188cu or rtl8188ru.

Larry

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-06 14:59   ` Kalle Valo
  2015-09-06 17:06     ` Larry Finger
@ 2015-09-07  1:40     ` Jes Sorensen
  2015-09-07 13:20       ` Kalle Valo
  1 sibling, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-09-07  1:40 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Larry.Finger

Kalle Valo <kvalo@codeaurora.org> writes:
> Jes.Sorensen@redhat.com writes:
>
>> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>>
>> This is an alternate driver for a number of Realtek WiFi USB devices,
>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>> It was written from scratch utilizing the Linux mac80211 stack.
>>
>> After spending months cleaning up the vendor provided rtl8723au
>> driver, which comes with it's own 802.11 stack included, I decided to
>> rewrite this driver from the bottom up.
>>
>> Many thanks to Johannes Berg for 802.11 insights and help and Larry
>> Finger for help with the vendor driver.
>>
>> The full git log for the development of this driver can be found here:
>> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>>     branch rtl8723au-mac80211
>>
>> This driver is still under development, but has proven to be very
>> stable for me. It currently supports station mode only. It has support
>> for OFDM and CCK rates, as well as AMPDU. It does lack certain
>> features found in the staging driver, such as power management and
>> 40MHz channel support. In addition it does not support AD-HOC, AP, and
>> monitor mode support at this point.
>>
>> The driver is known to work with the following devices:
>> Lenovo Yoga (rtl8723au)
>> TP-Link TL-WN823N (rtl8192cu)
>> Etekcity 6R (rtl8188cu)
>> Daffodil LAN03 (rtl8188cu)
>> Alfa AWUS036NHR (rtl8188ru)
>>
>> Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
>
> You forgot v2 from the subject.

I'llk send a v3 later fixing up some of the problems people have
reported.

>> v2: Contains fixes for problems reported by Larry Finger
>> ---
>
> Changelog should be under "---" line.
>
>> +static int rtl8xxxu_debug /* = 0 */; /* Avoid pointless checkpatch noise */
>
> Either assign it to zero or ignore the checkpatch warning, but please
> don't do this.

Problem is if I leave the = 0 some people will send pointless patches to
change it. The above gets checkpatch to shut up while leaving the
indication in place.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-06 17:06     ` Larry Finger
@ 2015-09-07  1:41       ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-07  1:41 UTC (permalink / raw)
  To: Larry Finger; +Cc: Kalle Valo, linux-wireless

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 09/06/2015 09:59 AM, Kalle Valo wrote:
>> Jes.Sorensen@redhat.com writes:
>>
>>> From: Jes Sorensen <Jes.Sorensen@redhat.com>
>>>
>>> This is an alternate driver for a number of Realtek WiFi USB devices,
>>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>>> It was written from scratch utilizing the Linux mac80211 stack.
>>>
>>> After spending months cleaning up the vendor provided rtl8723au
>>> driver, which comes with it's own 802.11 stack included, I decided to
>>> rewrite this driver from the bottom up.
>>>
>>> Many thanks to Johannes Berg for 802.11 insights and help and Larry
>>> Finger for help with the vendor driver.
>>>
>>> The full git log for the development of this driver can be found here:
>>> git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
>>>      branch rtl8723au-mac80211
>>>
>>> This driver is still under development, but has proven to be very
>>> stable for me. It currently supports station mode only. It has support
>>> for OFDM and CCK rates, as well as AMPDU. It does lack certain
>>> features found in the staging driver, such as power management and
>>> 40MHz channel support. In addition it does not support AD-HOC, AP, and
>>> monitor mode support at this point.
>>>
>>> The driver is known to work with the following devices:
>>> Lenovo Yoga (rtl8723au)
>>> TP-Link TL-WN823N (rtl8192cu)
>>> Etekcity 6R (rtl8188cu)
>>> Daffodil LAN03 (rtl8188cu)
>>> Alfa AWUS036NHR (rtl8188ru)
>
> One other comment is that using lower case such as rtl8723au indicates
> a driver, whereas RTL8723AU is a device. There are no drivers
> rtl8188cu or rtl8188ru.

I don't see this in general - I had upper case in some places in the
driver but it was awful to look at, especially in the dmesg output.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-06 14:43 ` [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Kalle Valo
  2015-09-06 17:03   ` Larry Finger
@ 2015-09-07  1:45   ` Jes Sorensen
  2015-09-07  4:24     ` Jes Sorensen
  2015-09-07  9:17     ` Kalle Valo
  1 sibling, 2 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-07  1:45 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Larry.Finger

Kalle Valo <kvalo@codeaurora.org> writes:
> Jes.Sorensen@redhat.com writes:
>
>> Per default only devices I have actually tested will be enabled. If
>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>> test results back to me.
>>
>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>> to which module you load and/or use modprobe blacklists.
>
> May clash? So how does this work in practise? Is the clash referring
> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>
> I think we should only have one driver automatically supporting certain
> hardware, and not have a driver randomly chosen and forcing users to use
> a blacklist.

We already have the clash, if you enable CONFIG_RTL8192U in staging it
clashes with rtlwifi's CONFIG_RTL8192CU. Ripping out the above two
drivers at this point isn't going to do users any good.

> Also how do we make sure that distros don't enable
> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
> without thinking.

Some distros enable staging whether you ask them or not. I think
CONFIG_RTL8XXXYU_UNTESTED is pretty safe and will most likely just work
for the devices on that list, but the driver will spit out a warning
asking the person to report test results to me.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07  1:45   ` Jes Sorensen
@ 2015-09-07  4:24     ` Jes Sorensen
  2015-09-07  8:53       ` Kalle Valo
  2015-09-07  9:17     ` Kalle Valo
  1 sibling, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-09-07  4:24 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Larry.Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:
> Kalle Valo <kvalo@codeaurora.org> writes:
>> Jes.Sorensen@redhat.com writes:
>>
>>> Per default only devices I have actually tested will be enabled. If
>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>> test results back to me.
>>>
>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>> to which module you load and/or use modprobe blacklists.
>>
>> May clash? So how does this work in practise? Is the clash referring
>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>
>> I think we should only have one driver automatically supporting certain
>> hardware, and not have a driver randomly chosen and forcing users to use
>> a blacklist.
>
> We already have the clash, if you enable CONFIG_RTL8192U in staging it
> clashes with rtlwifi's CONFIG_RTL8192CU. Ripping out the above two
> drivers at this point isn't going to do users any good.
>
>> Also how do we make sure that distros don't enable
>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>> without thinking.
>
> Some distros enable staging whether you ask them or not. I think
> CONFIG_RTL8XXXYU_UNTESTED is pretty safe and will most likely just work
> for the devices on that list, but the driver will spit out a warning
> asking the person to report test results to me.

Just one more note - we could put UNTESTED under EXPERIMENTAL

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07  4:24     ` Jes Sorensen
@ 2015-09-07  8:53       ` Kalle Valo
  0 siblings, 0 replies; 68+ messages in thread
From: Kalle Valo @ 2015-09-07  8:53 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, Larry.Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:

>>> Also how do we make sure that distros don't enable
>>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>>> without thinking.
>>
>> Some distros enable staging whether you ask them or not. I think
>> CONFIG_RTL8XXXYU_UNTESTED is pretty safe and will most likely just work
>> for the devices on that list, but the driver will spit out a warning
>> asking the person to report test results to me.
>
> Just one more note - we could put UNTESTED under EXPERIMENTAL

I think that's a good idea. Does anyone know if the distros use features
which depend on EXPERIMENTAL? I hope not.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-06 17:03   ` Larry Finger
@ 2015-09-07  9:06     ` Kalle Valo
  2015-09-07 15:35       ` Larry Finger
  2015-09-08 21:13       ` Jes Sorensen
  2015-09-08 21:01     ` Jes Sorensen
  1 sibling, 2 replies; 68+ messages in thread
From: Kalle Valo @ 2015-09-07  9:06 UTC (permalink / raw)
  To: Larry Finger; +Cc: Jes.Sorensen, linux-wireless

Larry Finger <Larry.Finger@lwfinger.net> writes:

> On 09/06/2015 09:43 AM, Kalle Valo wrote:
>> Jes.Sorensen@redhat.com writes:
>>
>>> Per default only devices I have actually tested will be enabled. If
>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>> test results back to me.
>>>
>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>> to which module you load and/or use modprobe blacklists.
>>
>> May clash? So how does this work in practise? Is the clash referring
>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>
>> I think we should only have one driver automatically supporting certain
>> hardware, and not have a driver randomly chosen and forcing users to use
>> a blacklist.
>
> I agree, in principle, but there will be difficulties in the
> implementation, at least in the short term.
>
> At the moment, the only driver that has a conflict with rtl8xxxu is
> rtl8192cu. Although rtl8xxxu is surprisingly more stable that
> rtl8192cu, the latter has more features, which is may be the reason
> for better stability. Driver rtl8xxxu does not handle any 40 MHz
> channels, nor can it become an AP either with hostapd or with
> NetworkManager. For those reasons, rtl819cu has to remain the standard
> driver for RTL81{88,92}CU devices until rtl8xxxu is improved. Anyone
> that wants to try the new driver will need to use blacklists.

But how do we make sure that for normal users rtl8192cu is always loaded
and not rtl8xxxu (until we decide to make the switch)? What I'm worried
is that normal distro users would use rtl8xxxu before it's ready for
their device.

> We can make changes in the Kconfig help texts that clarify the
> situation, but that will not help the user of kernels built by the
> distros.

Exactly. We should not create any regressions to existing setups,
everything should work as they did before. Kconfig options or blacklist
tweaking is not an acceptable way to handle that, it should be
automatic.

>> Also how do we make sure that distros don't enable
>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>> without thinking.
>
> It will not necessarily depend on whether CONFIG_RTL8XXXU_UNTESTED is
> enabled or not. Some of the affected devices are in the tested
> category.

Ok. Can't we start just rtl8xxxu having just devices NOT supported by
rtlwifi drivers? All other devices would be under
CONFIG_RTL8XXXU_UNTESTED until we think the support is ready and we can
make the switch by moving from untested to tested category. And at the
same time disable/remove those devices from rtlwifi.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07  1:45   ` Jes Sorensen
  2015-09-07  4:24     ` Jes Sorensen
@ 2015-09-07  9:17     ` Kalle Valo
  2015-09-08 21:24       ` Jes Sorensen
  1 sibling, 1 reply; 68+ messages in thread
From: Kalle Valo @ 2015-09-07  9:17 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, Larry.Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:

> Kalle Valo <kvalo@codeaurora.org> writes:
>> Jes.Sorensen@redhat.com writes:
>>
>>> Per default only devices I have actually tested will be enabled. If
>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>> test results back to me.
>>>
>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>> to which module you load and/or use modprobe blacklists.
>>
>> May clash? So how does this work in practise? Is the clash referring
>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>
>> I think we should only have one driver automatically supporting certain
>> hardware, and not have a driver randomly chosen and forcing users to use
>> a blacklist.
>
> We already have the clash, if you enable CONFIG_RTL8192U in staging it
> clashes with rtlwifi's CONFIG_RTL8192CU. Ripping out the above two
> drivers at this point isn't going to do users any good.

I'm not saying about we should remove drivers, my worry is only that we
don't have two drivers competing about same devices in a normal distro
kernel. We should _by default_ not have two drivers claiming support for
the same device, developer's can of course enable this via experimental
options etc.

>> Also how do we make sure that distros don't enable
>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>> without thinking.
>
> Some distros enable staging whether you ask them or not.

Sure, that's up to them. I don't care what's in staging so I can't
really comment about that, this is only in context of
drivers/net/wireless/.

> I think CONFIG_RTL8XXXYU_UNTESTED is pretty safe and will most likely
> just work for the devices on that list, but the driver will spit out a
> warning asking the person to report test results to me.

That sounds good. Let's just make it as obvious as possible that distros
and normal users should enable that option.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-07  1:40     ` Jes Sorensen
@ 2015-09-07 13:20       ` Kalle Valo
  2015-09-07 21:08         ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Kalle Valo @ 2015-09-07 13:20 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: linux-wireless, Larry.Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:

>>> +static int rtl8xxxu_debug /* = 0 */; /* Avoid pointless checkpatch noise */
>>
>> Either assign it to zero or ignore the checkpatch warning, but please
>> don't do this.
>
> Problem is if I leave the = 0 some people will send pointless patches to
> change it. The above gets checkpatch to shut up while leaving the
> indication in place.

Yeah, I guessed that but this is just silly. If it annoys so much fix
the checkpatch script or really assign it to zero, not this kind of
comment trickery.

-- 
Kalle Valo

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07  9:06     ` Kalle Valo
@ 2015-09-07 15:35       ` Larry Finger
  2015-09-08 21:04         ` Jes Sorensen
  2015-09-08 21:13       ` Jes Sorensen
  1 sibling, 1 reply; 68+ messages in thread
From: Larry Finger @ 2015-09-07 15:35 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Jes.Sorensen, linux-wireless

On 09/07/2015 04:06 AM, Kalle Valo wrote:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>
>> On 09/06/2015 09:43 AM, Kalle Valo wrote:
>>> Jes.Sorensen@redhat.com writes:
>>>
>>>> Per default only devices I have actually tested will be enabled. If
>>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>>> test results back to me.
>>>>
>>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>>> to which module you load and/or use modprobe blacklists.
>>>
>>> May clash? So how does this work in practise? Is the clash referring
>>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>>
>>> I think we should only have one driver automatically supporting certain
>>> hardware, and not have a driver randomly chosen and forcing users to use
>>> a blacklist.
>>
>> I agree, in principle, but there will be difficulties in the
>> implementation, at least in the short term.
>>
>> At the moment, the only driver that has a conflict with rtl8xxxu is
>> rtl8192cu. Although rtl8xxxu is surprisingly more stable that
>> rtl8192cu, the latter has more features, which is may be the reason
>> for better stability. Driver rtl8xxxu does not handle any 40 MHz
>> channels, nor can it become an AP either with hostapd or with
>> NetworkManager. For those reasons, rtl819cu has to remain the standard
>> driver for RTL81{88,92}CU devices until rtl8xxxu is improved. Anyone
>> that wants to try the new driver will need to use blacklists.
>
> But how do we make sure that for normal users rtl8192cu is always loaded
> and not rtl8xxxu (until we decide to make the switch)? What I'm worried
> is that normal distro users would use rtl8xxxu before it's ready for
> their device.
>
>> We can make changes in the Kconfig help texts that clarify the
>> situation, but that will not help the user of kernels built by the
>> distros.
>
> Exactly. We should not create any regressions to existing setups,
> everything should work as they did before. Kconfig options or blacklist
> tweaking is not an acceptable way to handle that, it should be
> automatic.
>
>>> Also how do we make sure that distros don't enable
>>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>>> without thinking.
>>
>> It will not necessarily depend on whether CONFIG_RTL8XXXU_UNTESTED is
>> enabled or not. Some of the affected devices are in the tested
>> category.
>
> Ok. Can't we start just rtl8xxxu having just devices NOT supported by
> rtlwifi drivers? All other devices would be under
> CONFIG_RTL8XXXU_UNTESTED until we think the support is ready and we can
> make the switch by moving from untested to tested category. And at the
> same time disable/remove those devices from rtlwifi.

Yes, that will work as long as we make CONFIG_RTL8XXXU_UNTESTED be EXPERIMENTAL 
to keep the distros from enabling it. In addition, a separate GitHub repo for 
rtl8xxxu should be made available with conditional code added to enable builds 
for kernels 3.10 or later. Then users that complain about some problem with 
rtl8192cu can be directed to that driver.

Larry



^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-07 13:20       ` Kalle Valo
@ 2015-09-07 21:08         ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-07 21:08 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Larry.Finger

Kalle Valo <kvalo@codeaurora.org> writes:
> Jes Sorensen <Jes.Sorensen@redhat.com> writes:
>
>>>> +static int rtl8xxxu_debug /* = 0 */; /* Avoid pointless checkpatch noise */
>>>
>>> Either assign it to zero or ignore the checkpatch warning, but please
>>> don't do this.
>>
>> Problem is if I leave the = 0 some people will send pointless patches to
>> change it. The above gets checkpatch to shut up while leaving the
>> indication in place.
>
> Yeah, I guessed that but this is just silly. If it annoys so much fix
> the checkpatch script or really assign it to zero, not this kind of
> comment trickery.

I'll remove it. The real problem here is that checkpatch has gotten to
the point where it is at times causing more harm than good. It is
unlikely to get fixed, get there is a small group who see it as their
mission to force their ways upon others, no matter whether it matters or
not.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-06 17:03   ` Larry Finger
  2015-09-07  9:06     ` Kalle Valo
@ 2015-09-08 21:01     ` Jes Sorensen
  2015-09-09 10:51       ` Bruno Randolf
  1 sibling, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-09-08 21:01 UTC (permalink / raw)
  To: Larry Finger; +Cc: Kalle Valo, linux-wireless

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 09/06/2015 09:43 AM, Kalle Valo wrote:
>> Jes.Sorensen@redhat.com writes:
>>
>>> Per default only devices I have actually tested will be enabled. If
>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>> test results back to me.
>>>
>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>> to which module you load and/or use modprobe blacklists.
>>
>> May clash? So how does this work in practise? Is the clash referring
>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>
>> I think we should only have one driver automatically supporting certain
>> hardware, and not have a driver randomly chosen and forcing users to use
>> a blacklist.
>
> I agree, in principle, but there will be difficulties in the
> implementation, at least in the short term.
>
> At the moment, the only driver that has a conflict with rtl8xxxu is
> rtl8192cu. Although rtl8xxxu is surprisingly more stable that
> rtl8192cu, the latter has more features, which is may be the reason
> for better stability. Driver rtl8xxxu does not handle any 40 MHz
> channels, nor can it become an AP either with hostapd or with
> NetworkManager. For those reasons, rtl819cu has to remain the standard
> driver for RTL81{88,92}CU devices until rtl8xxxu is improved. Anyone
> that wants to try the new driver will need to use blacklists.

I do not fully agree on this. In my testing I found rtl8192cu rather
unstable, to the point of not being usable. It would lock up for me
after a short while. I have seen this happen with mulitple different
adapters. I suspect this is the reason why drivers/staging/rtl8192u is
still sitting in the kernel tree.

It is true the rtl8xxxu doesn't support 40MHz channels, but reality is
few people actually use them since it's almost impossible to get free
channel access without clashes these days. Now I still intend to add
support for 40MHz, it has just not been on the top of the priority list
so far. Finding a place to test it is kinda hard when you live in the
middle of a city like New York :)

My take is that the majority of users mostly care about station support
and for them rtl8xxxu will be much preferred to rtl8192cu.

Basically I don't think there is a one solution fits all to this.
Whether we like it, we will have to accept that there are going to be
multiple drivers around for these chips for a while.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07 15:35       ` Larry Finger
@ 2015-09-08 21:04         ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-08 21:04 UTC (permalink / raw)
  To: Larry Finger; +Cc: Kalle Valo, linux-wireless

Larry Finger <Larry.Finger@lwfinger.net> writes:
> On 09/07/2015 04:06 AM, Kalle Valo wrote:
>> Larry Finger <Larry.Finger@lwfinger.net> writes:
>> Ok. Can't we start just rtl8xxxu having just devices NOT supported by
>> rtlwifi drivers? All other devices would be under
>> CONFIG_RTL8XXXU_UNTESTED until we think the support is ready and we can
>> make the switch by moving from untested to tested category. And at the
>> same time disable/remove those devices from rtlwifi.
>
> Yes, that will work as long as we make CONFIG_RTL8XXXU_UNTESTED be
> EXPERIMENTAL to keep the distros from enabling it. In addition, a
> separate GitHub repo for rtl8xxxu should be made available with
> conditional code added to enable builds for kernels 3.10 or
> later. Then users that complain about some problem with rtl8192cu can
> be directed to that driver.

If someone wants to maintain a backported version of the driver for
certain kernels, that is fine with me. It should probably be in the form
of an out-of tree build package, so maybe simply a tarball would
suffice?

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07  9:06     ` Kalle Valo
  2015-09-07 15:35       ` Larry Finger
@ 2015-09-08 21:13       ` Jes Sorensen
  1 sibling, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-08 21:13 UTC (permalink / raw)
  To: Kalle Valo; +Cc: Larry Finger, linux-wireless

Kalle Valo <kvalo@codeaurora.org> writes:
> Larry Finger <Larry.Finger@lwfinger.net> writes:
>
>> On 09/06/2015 09:43 AM, Kalle Valo wrote:
>>> Jes.Sorensen@redhat.com writes:
>>>
>>>> Per default only devices I have actually tested will be enabled. If
>>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>>> test results back to me.
>>>>
>>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>>> to which module you load and/or use modprobe blacklists.
>>>
>>> May clash? So how does this work in practise? Is the clash referring
>>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>>
>>> I think we should only have one driver automatically supporting certain
>>> hardware, and not have a driver randomly chosen and forcing users to use
>>> a blacklist.
>>
>> I agree, in principle, but there will be difficulties in the
>> implementation, at least in the short term.
>>
>> At the moment, the only driver that has a conflict with rtl8xxxu is
>> rtl8192cu. Although rtl8xxxu is surprisingly more stable that
>> rtl8192cu, the latter has more features, which is may be the reason
>> for better stability. Driver rtl8xxxu does not handle any 40 MHz
>> channels, nor can it become an AP either with hostapd or with
>> NetworkManager. For those reasons, rtl819cu has to remain the standard
>> driver for RTL81{88,92}CU devices until rtl8xxxu is improved. Anyone
>> that wants to try the new driver will need to use blacklists.
>
> But how do we make sure that for normal users rtl8192cu is always loaded
> and not rtl8xxxu (until we decide to make the switch)? What I'm worried
> is that normal distro users would use rtl8xxxu before it's ready for
> their device.

It's a bit of a chicken and egg situation. We could default it to only
enable 8723au support, but then nobody would really test it. Right now I
believe rtlwifi and r8723au will auto-load first, at least I had to
blacklist them here to not have them get in the way.

>> We can make changes in the Kconfig help texts that clarify the
>> situation, but that will not help the user of kernels built by the
>> distros.
>
> Exactly. We should not create any regressions to existing setups,
> everything should work as they did before. Kconfig options or blacklist
> tweaking is not an acceptable way to handle that, it should be
> automatic.

Problem for me is that the current default driver is unstable to the
point of being unusable.

>>> Also how do we make sure that distros don't enable
>>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>>> without thinking.
>>
>> It will not necessarily depend on whether CONFIG_RTL8XXXU_UNTESTED is
>> enabled or not. Some of the affected devices are in the tested
>> category.
>
> Ok. Can't we start just rtl8xxxu having just devices NOT supported by
> rtlwifi drivers? All other devices would be under
> CONFIG_RTL8XXXU_UNTESTED until we think the support is ready and we can
> make the switch by moving from untested to tested category. And at the
> same time disable/remove those devices from rtlwifi.

I don't like this idea very much. We want people to actually test those
devices, and if they keep getting rtl8192cu they won't get to it. A lot
of the users who have problems with these devices are not the ones who
will build their own kernels all the time. Maybe if it could be done
with a module parameter?

The real question here is how big a percentage of users really rely on
AP and mesh mode compared to station mode.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-07  9:17     ` Kalle Valo
@ 2015-09-08 21:24       ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-09-08 21:24 UTC (permalink / raw)
  To: Kalle Valo; +Cc: linux-wireless, Larry.Finger

Kalle Valo <kvalo@codeaurora.org> writes:
> Jes Sorensen <Jes.Sorensen@redhat.com> writes:
>
>> Kalle Valo <kvalo@codeaurora.org> writes:
>>> Jes.Sorensen@redhat.com writes:
>>>
>>>> Per default only devices I have actually tested will be enabled. If
>>>> you are interested in trying it out with other 8188cu/8188ru/819[12]cu
>>>> dongles, you need to enable CONFIG_RTL8XXXU_UNTESTED. Please report
>>>> test results back to me.
>>>>
>>>> Note if you enable this driver, it may clash with CONFIG_RTL8192U,
>>>> CONFIG_R8723AU, and CONFIG_RTL8192CU (rtlwifi). Please pay attention
>>>> to which module you load and/or use modprobe blacklists.
>>>
>>> May clash? So how does this work in practise? Is the clash referring
>>> CONFIG_RTL8XXXU_UNTESTED enabled or disabled?
>>>
>>> I think we should only have one driver automatically supporting certain
>>> hardware, and not have a driver randomly chosen and forcing users to use
>>> a blacklist.
>>
>> We already have the clash, if you enable CONFIG_RTL8192U in staging it
>> clashes with rtlwifi's CONFIG_RTL8192CU. Ripping out the above two
>> drivers at this point isn't going to do users any good.
>
> I'm not saying about we should remove drivers, my worry is only that we
> don't have two drivers competing about same devices in a normal distro
> kernel. We should _by default_ not have two drivers claiming support for
> the same device, developer's can of course enable this via experimental
> options etc.
>
>>> Also how do we make sure that distros don't enable
>>> CONFIG_RTL8XXXU_UNTESTED? They are notarious of enabling kconfig options
>>> without thinking.
>>
>> Some distros enable staging whether you ask them or not.
>
> Sure, that's up to them. I don't care what's in staging so I can't
> really comment about that, this is only in context of
> drivers/net/wireless/.

I'm with you, my point is just that we already have multiple drivers
claming this. It is not a new situation :( Right now the distros enable
the rtl drivers in staging because it is the only way to get support for
a number of realtek devices. At least OpenSuSE and Debian seem to be
enabling CONFIG_RTL8192U right now, while Fedora doesn't.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au
  2015-09-08 21:01     ` Jes Sorensen
@ 2015-09-09 10:51       ` Bruno Randolf
  0 siblings, 0 replies; 68+ messages in thread
From: Bruno Randolf @ 2015-09-09 10:51 UTC (permalink / raw)
  To: Jes Sorensen, Larry Finger; +Cc: Kalle Valo, linux-wireless

On 09/08/2015 10:01 PM, Jes Sorensen wrote:
> I do not fully agree on this. In my testing I found rtl8192cu rather
> unstable, to the point of not being usable. It would lock up for me
> after a short while. I have seen this happen with mulitple different
> adapters. I suspect this is the reason why drivers/staging/rtl8192u is
> still sitting in the kernel tree.

I second this. Problems with rtc8192cu have been mentioned on this list
before: http://www.spinics.net/lists/linux-wireless/msg138538.html
I recently saw similar problems in STA mode as well.

> My take is that the majority of users mostly care about station support
> and for them rtl8xxxu will be much preferred to rtl8192cu.

Right. Users who need AP or IBSS mode can usually be expected to be able
to change kernel configurations or blacklist modules.

Also we hope that rtl8xxxu will be extended in the future to support
IBSS and AP mode as well! :)

bruno


^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-05  4:02                 ` Sujith Manoharan
@ 2015-09-17 16:46                   ` Johannes Berg
  2015-10-05 18:49                     ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-09-17 16:46 UTC (permalink / raw)
  To: Sujith Manoharan, Jes Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger

On Sat, 2015-09-05 at 09:32 +0530, Sujith Manoharan wrote:
> Jes Sorensen wrote:
> > > Ah, this makes sense. There's an rc_update call or something like 
> > > that,
> > > that might have the requisite information. Not really sure off 
> > > the top
> > > of my head.
> 
> ieee80211_sta doesn't contain the preamble information, though ?
> 
> The bss information holds the short preamble information, so that can
> probably be used - using BSS_CHANGED_ERP_PREAMBLE.

Yes, this is a good point, and the preamble can't really be different
for different stations since all the stations in the BSS (and even
outside it on the same channel) must be able to decode it.

So yeah - Jes, you can remove that and use the
BSS_CHANGED_ERP_PREAMBLE.


johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-09-17 16:46                   ` Johannes Berg
@ 2015-10-05 18:49                     ` Jes Sorensen
  2015-10-05 18:56                       ` Johannes Berg
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-10-05 18:49 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Sat, 2015-09-05 at 09:32 +0530, Sujith Manoharan wrote:
>> Jes Sorensen wrote:
>> > > Ah, this makes sense. There's an rc_update call or something like 
>> > > that,
>> > > that might have the requisite information. Not really sure off 
>> > > the top
>> > > of my head.
>> 
>> ieee80211_sta doesn't contain the preamble information, though ?
>> 
>> The bss information holds the short preamble information, so that can
>> probably be used - using BSS_CHANGED_ERP_PREAMBLE.
>
> Yes, this is a good point, and the preamble can't really be different
> for different stations since all the stations in the BSS (and even
> outside it on the same channel) must be able to decode it.
>
> So yeah - Jes, you can remove that and use the
> BSS_CHANGED_ERP_PREAMBLE.

Finally went back to look at this - I believe this is exactly what I am
doing in the driver right now. Pulling the short_preamble info from
BSS_CHANGED_ERP_PREAMBLE and storing it sta->drv_priv for use in the
tx function.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-05 18:49                     ` Jes Sorensen
@ 2015-10-05 18:56                       ` Johannes Berg
  2015-10-05 19:04                         ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-10-05 18:56 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

On Mon, 2015-10-05 at 14:49 -0400, Jes Sorensen wrote:
> 
> Finally went back to look at this - I believe this is exactly what I am
> doing in the driver right now. Pulling the short_preamble info from
> BSS_CHANGED_ERP_PREAMBLE and storing it sta->drv_priv for use in the
> tx function.
> 

You can't really be doing that since you don't get a sta pointer with
BSS_CHANGED_ERP_PREAMBLE?

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-05 18:56                       ` Johannes Berg
@ 2015-10-05 19:04                         ` Jes Sorensen
  2015-10-05 19:12                           ` Johannes Berg
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-10-05 19:04 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Mon, 2015-10-05 at 14:49 -0400, Jes Sorensen wrote:
>> 
>> Finally went back to look at this - I believe this is exactly what I am
>> doing in the driver right now. Pulling the short_preamble info from
>> BSS_CHANGED_ERP_PREAMBLE and storing it sta->drv_priv for use in the
>> tx function.
>> 
>
> You can't really be doing that since you don't get a sta pointer with
> BSS_CHANGED_ERP_PREAMBLE?

I have this in the code - that said, I may not be getting a pointer back
ever?

	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
		dev_dbg(dev, "Changed ERP_PREAMBLE: Use short preamble %i\n",
			bss_conf->use_short_preamble);
		val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
		if (bss_conf->use_short_preamble)
			val32 |= RSR_ACK_SHORT_PREAMBLE;
		else
			val32 &= ~RSR_ACK_SHORT_PREAMBLE;
		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);

		rcu_read_lock();
		sta = ieee80211_find_sta(vif, bss_conf->bssid);
		if (sta) {
			sta_priv = (struct rtl8xxxu_sta_priv *)sta->drv_priv;
			if (bss_conf->use_short_preamble)
				sta_priv->short_preamble = true;
			else
				sta_priv->short_preamble = false;
		}
		rcu_read_unlock();
	}

So what was it you were suggesting instead? I think I am confused now.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-05 19:04                         ` Jes Sorensen
@ 2015-10-05 19:12                           ` Johannes Berg
  2015-10-05 19:19                             ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-10-05 19:12 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

On Mon, 2015-10-05 at 15:04 -0400, Jes Sorensen wrote:
> 
> I have this in the code - that said, I may not be getting a pointer 
> back ever?
> 
> 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
> ...
> 		sta = ieee80211_find_sta(vif, bss_conf->bssid);
> 		if (sta) {
> 			sta_priv = (struct rtl8xxxu_sta_priv *)sta
> ->drv_priv;
> 			if (bss_conf->use_short_preamble)
> 				sta_priv->short_preamble = true;
> 			else
> 				sta_priv->short_preamble = false;
> 

Ah, ok. You'd of course get a pointer back here - but it's pointless.

You might as well store the value in some private vif data, or perhaps
just use vif->bss_conf.use_short_preamble in the place that you're now
using sta_priv->short_preamble - the point was that a per-station
setting of short-preamble doesn't make sense, it needs to be per-vif.

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-05 19:12                           ` Johannes Berg
@ 2015-10-05 19:19                             ` Jes Sorensen
  2015-10-05 19:20                               ` Johannes Berg
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-10-05 19:19 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Mon, 2015-10-05 at 15:04 -0400, Jes Sorensen wrote:
>> 
>> I have this in the code - that said, I may not be getting a pointer 
>> back ever?
>> 
>> 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
>> ...
>> 		sta = ieee80211_find_sta(vif, bss_conf->bssid);
>> 		if (sta) {
>> 			sta_priv = (struct rtl8xxxu_sta_priv *)sta
>> ->drv_priv;
>> 			if (bss_conf->use_short_preamble)
>> 				sta_priv->short_preamble = true;
>> 			else
>> 				sta_priv->short_preamble = false;
>> 
>
> Ah, ok. You'd of course get a pointer back here - but it's pointless.
>
> You might as well store the value in some private vif data, or perhaps
> just use vif->bss_conf.use_short_preamble in the place that you're now
> using sta_priv->short_preamble - the point was that a per-station
> setting of short-preamble doesn't make sense, it needs to be per-vif.

I see - what is the correct way to get to the vif from with the .tx()
function then?

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-05 19:19                             ` Jes Sorensen
@ 2015-10-05 19:20                               ` Johannes Berg
  2015-10-05 19:53                                 ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Johannes Berg @ 2015-10-05 19:20 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

On Mon, 2015-10-05 at 15:19 -0400, Jes Sorensen wrote:
> Johannes Berg <johannes@sipsolutions.net> writes:
> > On Mon, 2015-10-05 at 15:04 -0400, Jes Sorensen wrote:
> > > 
> > > I have this in the code - that said, I may not be getting a 
> > > pointer 
> > > back ever?
> > > 
> > > 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
> > > ...
> > > 		sta = ieee80211_find_sta(vif, bss_conf->bssid);
> > > 		if (sta) {
> > > 			sta_priv = (struct rtl8xxxu_sta_priv 
> > > *)sta
> > > ->drv_priv;
> > > 			if (bss_conf->use_short_preamble)
> > > 				sta_priv->short_preamble = true;
> > > 			else
> > > 				sta_priv->short_preamble = 
> > > false;
> > > 
> > 
> > Ah, ok. You'd of course get a pointer back here - but it's 
> > pointless.
> > 
> > You might as well store the value in some private vif data, or 
> > perhaps
> > just use vif->bss_conf.use_short_preamble in the place that you're 
> > now
> > using sta_priv->short_preamble - the point was that a per-station
> > setting of short-preamble doesn't make sense, it needs to be per
> > -vif.
> 
> I see - what is the correct way to get to the vif from with the .tx()
> function then?
> 

You have a pointer right there in the skb's cb (info) [though it might
be NULL in some rare cases]

johannes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-05 19:20                               ` Johannes Berg
@ 2015-10-05 19:53                                 ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-10-05 19:53 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Sujith Manoharan, linux-wireless, kvalo, Larry.Finger

Johannes Berg <johannes@sipsolutions.net> writes:
> On Mon, 2015-10-05 at 15:19 -0400, Jes Sorensen wrote:
>> Johannes Berg <johannes@sipsolutions.net> writes:
>> > On Mon, 2015-10-05 at 15:04 -0400, Jes Sorensen wrote:
>> > > 
>> > > I have this in the code - that said, I may not be getting a 
>> > > pointer 
>> > > back ever?
>> > > 
>> > > 	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
>> > > ...
>> > > 		sta = ieee80211_find_sta(vif, bss_conf->bssid);
>> > > 		if (sta) {
>> > > 			sta_priv = (struct rtl8xxxu_sta_priv 
>> > > *)sta
>> > > ->drv_priv;
>> > > 			if (bss_conf->use_short_preamble)
>> > > 				sta_priv->short_preamble = true;
>> > > 			else
>> > > 				sta_priv->short_preamble = 
>> > > false;
>> > > 
>> > 
>> > Ah, ok. You'd of course get a pointer back here - but it's 
>> > pointless.
>> > 
>> > You might as well store the value in some private vif data, or 
>> > perhaps
>> > just use vif->bss_conf.use_short_preamble in the place that you're 
>> > now
>> > using sta_priv->short_preamble - the point was that a per-station
>> > setting of short-preamble doesn't make sense, it needs to be per
>> > -vif.
>> 
>> I see - what is the correct way to get to the vif from with the .tx()
>> function then?
>
> You have a pointer right there in the skb's cb (info) [though it might
> be NULL in some rare cases]

Think I got it right now - this allowed me to get rid of the sta_priv
stuff as well.

Thanks a lot for the help!

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-08-29 21:18 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
  2015-08-30  4:42   ` Larry Finger
  2015-08-31 14:48   ` Johannes Berg
@ 2015-10-08 16:23   ` Jakub Sitnicki
  2015-10-08 19:09     ` Jes Sorensen
  2 siblings, 1 reply; 68+ messages in thread
From: Jakub Sitnicki @ 2015-10-08 16:23 UTC (permalink / raw)
  To: Jes.Sorensen; +Cc: linux-wireless, kvalo, Larry.Finger

Hi Jes,

On Sat, Aug 29, 2015 at 11:18 PM CEST, Jes.Sorensen@redhat.com wrote:
> This is an alternate driver for a number of Realtek WiFi USB devices,
> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
> It was written from scratch utilizing the Linux mac80211 stack.
>
> After spending months cleaning up the vendor provided rtl8723au
> driver, which comes with it's own 802.11 stack included, I decided to
> rewrite this driver from the bottom up.

In the long term, do you plan for this driver to support the
RTL8188EU-based devices as well?

I've been checking how far I can get through the rtl8xxxu initialization
using a TP-Link TL-WN725N dongle without changing too much.

Getting it up to read the EFUSE contents wasn't difficult but then you
need to parse it and first differences come to light.  Namely, TX power
levels are defined per each of 6 (not 3) channel groups, and power
differences are defined per TX path (as opposed to per channel group).
This is perhaps better described by the relevant structure from
rtl8188eu driver:

struct txpowerinfo24g {
	u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
	u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
	/* If only one tx, only BW20 and OFDM are used. */
	s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT];
	s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT];
	s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT];
	s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT];
};

AFAICT, in this regard, rtl8188eu driver has more in common with the
rtlwifi/rtl8188ee driver.

I'm curious what is your opinion on this.  In particular, do you see any
reason not to make an attempt to extend rtl8xxxu to support 8188EU
chips?

Thanks,
Jakub

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-08 16:23   ` Jakub Sitnicki
@ 2015-10-08 19:09     ` Jes Sorensen
  2015-10-08 20:33       ` Stefan Lippers-Hollmann
                         ` (2 more replies)
  0 siblings, 3 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-10-08 19:09 UTC (permalink / raw)
  To: Jakub Sitnicki; +Cc: linux-wireless, kvalo, Larry.Finger

Jakub Sitnicki <jsitnicki@gmail.com> writes:
> Hi Jes,
>
> On Sat, Aug 29, 2015 at 11:18 PM CEST, Jes.Sorensen@redhat.com wrote:
>> This is an alternate driver for a number of Realtek WiFi USB devices,
>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>> It was written from scratch utilizing the Linux mac80211 stack.
>>
>> After spending months cleaning up the vendor provided rtl8723au
>> driver, which comes with it's own 802.11 stack included, I decided to
>> rewrite this driver from the bottom up.
>
> In the long term, do you plan for this driver to support the
> RTL8188EU-based devices as well?

I have an 8188EU dongle in my wifi dongle pouch, together with several
other yet to be supported ones :) I am currently trying to get the
8723BU and 8192EU working, but I haven't had time to work much on the
8188EU yet.

> I've been checking how far I can get through the rtl8xxxu initialization
> using a TP-Link TL-WN725N dongle without changing too much.
>
> Getting it up to read the EFUSE contents wasn't difficult but then you
> need to parse it and first differences come to light.  Namely, TX power
> levels are defined per each of 6 (not 3) channel groups, and power
> differences are defined per TX path (as opposed to per channel group).
> This is perhaps better described by the relevant structure from
> rtl8188eu driver:
>
> struct txpowerinfo24g {
> 	u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
> 	u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
> 	/* If only one tx, only BW20 and OFDM are used. */
> 	s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT];
> 	s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT];
> 	s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT];
> 	s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT];
> };
>
> AFAICT, in this regard, rtl8188eu driver has more in common with the
> rtlwifi/rtl8188ee driver.
>
> I'm curious what is your opinion on this.  In particular, do you see any
> reason not to make an attempt to extend rtl8xxxu to support 8188EU
> chips?

Parsing the efuse is normally fairly easy, if you have a reference to
the layout. It can be deducted from the vendor driver code. The layout
pretty much differ for each chip, but I have seen enough of them by now
that I can parse most of it by looking at the hex dump.

I think the 8188EU uses IOL, which is an enhanced firmware assist API.
That will change the programming a bit, but I think it's well within
scope for this driver to support this as well.

In other words, it is my plan to look at the 8188EU. If you get it going
before me, I am very happy to work with you on integrating the patches.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-08 19:09     ` Jes Sorensen
@ 2015-10-08 20:33       ` Stefan Lippers-Hollmann
  2015-10-08 21:06         ` Jes Sorensen
  2015-10-08 21:03       ` Jes Sorensen
  2015-10-10  4:17       ` Taehee Yoo
  2 siblings, 1 reply; 68+ messages in thread
From: Stefan Lippers-Hollmann @ 2015-10-08 20:33 UTC (permalink / raw)
  To: Jes Sorensen; +Cc: Jakub Sitnicki, linux-wireless, kvalo, Larry.Finger

Hi

On 2015-10-08, Jes Sorensen wrote:
> Jakub Sitnicki <jsitnicki@gmail.com> writes:
> > Hi Jes,
> >
> > On Sat, Aug 29, 2015 at 11:18 PM CEST, Jes.Sorensen@redhat.com wrote:
> >> This is an alternate driver for a number of Realtek WiFi USB devices,
> >> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
> >> It was written from scratch utilizing the Linux mac80211 stack.
> >>
> >> After spending months cleaning up the vendor provided rtl8723au
> >> driver, which comes with it's own 802.11 stack included, I decided to
> >> rewrite this driver from the bottom up.
> >
> > In the long term, do you plan for this driver to support the
> > RTL8188EU-based devices as well?
> 
> I have an 8188EU dongle in my wifi dongle pouch, together with several
> other yet to be supported ones :) I am currently trying to get the
> 8723BU and 8192EU working, but I haven't had time to work much on the
> 8188EU yet.
[...]

I was wondering about a pretty similar question, do you see this driver 
as being potentially compatible with rtl8192su[1] or rtl8192du[2] devices
or are these too different[3]?

Regards
	Stefan Lippers-Hollmann

[1]	currently supported by the staging r8712u driver
	or https://github.com/chunkeey/rtl8192su
	ID 0bda:8171 Realtek Semiconductor Corp. RTL8188SU 802.11n WLAN Adapter
	ID 0bda:8172 Realtek Semiconductor Corp. RTL8191SU 802.11n WLAN Adapter
[2]	currently no mainline support, 
	https://github.com/lwfinger/rtl8192du/commits/kernel-version
	as a dual-band device coming in multiple flavours, this might
	be a bit harder to support.
	ID 0bda:8194 Realtek Semiconductor Corp.
[3]	they obviously aren't covered yet, as rtl8xxxu doesn't know
	about their USB IDs/ firmware or initialisation routines 
	(respectively 5 GHz support in case of rtl8192du).

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-08 19:09     ` Jes Sorensen
  2015-10-08 20:33       ` Stefan Lippers-Hollmann
@ 2015-10-08 21:03       ` Jes Sorensen
  2015-10-10  4:17       ` Taehee Yoo
  2 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-10-08 21:03 UTC (permalink / raw)
  To: Jakub Sitnicki; +Cc: linux-wireless, kvalo, Larry.Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:
> Jakub Sitnicki <jsitnicki@gmail.com> writes:
>> AFAICT, in this regard, rtl8188eu driver has more in common with the
>> rtlwifi/rtl8188ee driver.
>>
>> I'm curious what is your opinion on this.  In particular, do you see any
>> reason not to make an attempt to extend rtl8xxxu to support 8188EU
>> chips?
>
> Parsing the efuse is normally fairly easy, if you have a reference to
> the layout. It can be deducted from the vendor driver code. The layout
> pretty much differ for each chip, but I have seen enough of them by now
> that I can parse most of it by looking at the hex dump.
>
> I think the 8188EU uses IOL, which is an enhanced firmware assist API.
> That will change the programming a bit, but I think it's well within
> scope for this driver to support this as well.
>
> In other words, it is my plan to look at the 8188EU. If you get it going
> before me, I am very happy to work with you on integrating the patches.

Jakub,

Digging a bit further, it looks like the 8188EU, 8192EU, and 8723BU, use
a different RF module than the previous parts. They have far more RF
registers, so the code for reading/writing RF registers does not work as
is.

Hopefully shouldn't be too hard to fix, but it also mean that the RF
init table used for the older parts will not match whats needed for the
new parts.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-08 20:33       ` Stefan Lippers-Hollmann
@ 2015-10-08 21:06         ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-10-08 21:06 UTC (permalink / raw)
  To: Stefan Lippers-Hollmann
  Cc: Jakub Sitnicki, linux-wireless, kvalo, Larry.Finger

Stefan Lippers-Hollmann <s.l-h@gmx.de> writes:
> Hi
>
> On 2015-10-08, Jes Sorensen wrote:
>> I have an 8188EU dongle in my wifi dongle pouch, together with several
>> other yet to be supported ones :) I am currently trying to get the
>> 8723BU and 8192EU working, but I haven't had time to work much on the
>> 8188EU yet.
> [...]
>
> I was wondering about a pretty similar question, do you see this driver 
> as being potentially compatible with rtl8192su[1] or rtl8192du[2] devices
> or are these too different[3]?

Same answer :) My pouch also contains an 8192SU and an 8192DU dongle,
albeit I haven't looked much at that code at all so far.

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-08 19:09     ` Jes Sorensen
  2015-10-08 20:33       ` Stefan Lippers-Hollmann
  2015-10-08 21:03       ` Jes Sorensen
@ 2015-10-10  4:17       ` Taehee Yoo
  2 siblings, 0 replies; 68+ messages in thread
From: Taehee Yoo @ 2015-10-10  4:17 UTC (permalink / raw)
  To: Jes Sorensen, Larry Finger
  Cc: Jakub Sitnicki, linux-wireless@vger.kernel.org, Kalle Valo

2015-10-09 4:09 GMT+09:00 Jes Sorensen <Jes.Sorensen@redhat.com>:
> Jakub Sitnicki <jsitnicki@gmail.com> writes:
>> Hi Jes,
>>
>> On Sat, Aug 29, 2015 at 11:18 PM CEST, Jes.Sorensen@redhat.com wrote:
>>> This is an alternate driver for a number of Realtek WiFi USB devices,
>>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>>> It was written from scratch utilizing the Linux mac80211 stack.
>>>
>>> After spending months cleaning up the vendor provided rtl8723au
>>> driver, which comes with it's own 802.11 stack included, I decided to
>>> rewrite this driver from the bottom up.
>>
>> In the long term, do you plan for this driver to support the
>> RTL8188EU-based devices as well?
>
> I have an 8188EU dongle in my wifi dongle pouch, together with several
> other yet to be supported ones :) I am currently trying to get the
> 8723BU and 8192EU working, but I haven't had time to work much on the
> 8188EU yet.
>
>> I've been checking how far I can get through the rtl8xxxu initialization
>> using a TP-Link TL-WN725N dongle without changing too much.
>>
>> Getting it up to read the EFUSE contents wasn't difficult but then you
>> need to parse it and first differences come to light.  Namely, TX power
>> levels are defined per each of 6 (not 3) channel groups, and power
>> differences are defined per TX path (as opposed to per channel group).
>> This is perhaps better described by the relevant structure from
>> rtl8188eu driver:
>>
>> struct txpowerinfo24g {
>>       u8 IndexCCK_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
>>       u8 IndexBW40_Base[MAX_RF_PATH][MAX_CHNL_GROUP_24G];
>>       /* If only one tx, only BW20 and OFDM are used. */
>>       s8 CCK_Diff[MAX_RF_PATH][MAX_TX_COUNT];
>>       s8 OFDM_Diff[MAX_RF_PATH][MAX_TX_COUNT];
>>       s8 BW20_Diff[MAX_RF_PATH][MAX_TX_COUNT];
>>       s8 BW40_Diff[MAX_RF_PATH][MAX_TX_COUNT];
>> };
>>
>> AFAICT, in this regard, rtl8188eu driver has more in common with the
>> rtlwifi/rtl8188ee driver.
>>
>> I'm curious what is your opinion on this.  In particular, do you see any
>> reason not to make an attempt to extend rtl8xxxu to support 8188EU
>> chips?
>
> Parsing the efuse is normally fairly easy, if you have a reference to
> the layout. It can be deducted from the vendor driver code. The layout
> pretty much differ for each chip, but I have seen enough of them by now
> that I can parse most of it by looking at the hex dump.
>
> I think the 8188EU uses IOL, which is an enhanced firmware assist API.
> That will change the programming a bit, but I think it's well within
> scope for this driver to support this as well.
>
> In other words, it is my plan to look at the 8188EU. If you get it going
> before me, I am very happy to work with you on integrating the patches.
>
> Cheers,
> Jes
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


Hi

I am currently writing a rtl8188eu driver that is using rtlwifi.
I think this driver can help you to support the RTL8188EU chip.

https://github.com/TaeheeYoo/rtl8188eu

Thanks,
Taehee

^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-15  0:44 [PATCH v3 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
@ 2015-10-15  0:44 ` Jes.Sorensen
  2015-10-15 12:09   ` Bruno Randolf
  0 siblings, 1 reply; 68+ messages in thread
From: Jes.Sorensen @ 2015-10-15  0:44 UTC (permalink / raw)
  To: kvalo; +Cc: linux-wireless, Larry.Finger

From: Jes Sorensen <Jes.Sorensen@redhat.com>

This is an alternate driver for a number of Realtek WiFi USB devices,
including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
It was written from scratch utilizing the Linux mac80211 stack.

After spending months cleaning up the vendor provided rtl8723au
driver, which comes with it's own 802.11 stack included, I decided to
rewrite this driver from the bottom up.

Many thanks to Johannes Berg for 802.11 insights and help and Larry
Finger for help with the vendor driver.

The full git log for the development of this driver can be found here:
git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git
    branch rtl8723au-mac80211

This driver is still under development, but has proven to be very
stable for me. It currently supports station mode only. It has support
for OFDM and CCK rates. It does lack certain features found in the
staging driver, such as power management, AMPDU, and 40MHz channel
support. In addition it does not support AD-HOC, AP, and monitor mode
support at this point.

The driver is known to work with the following devices:
Lenovo Yoga (rtl8723au)
TP-Link TL-WN823N (rtl8192cu)
Etekcity 6R (rtl8188cu)
Daffodil LAN03 (rtl8188cu)
Alfa AWUS036NHR (rtl8188ru)

Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
---
v3:
  Obtain short-preamble information from the vif rather than keeping
  a sta_priv and carrying it around there. Suggested by Johannes Berg.
  Move driver to drivers/net/wireless/realtek/rtl8xxxu/

 MAINTAINERS                                        |    7 +
 drivers/net/wireless/Kconfig                       |    1 +
 drivers/net/wireless/realtek/Makefile              |    1 +
 drivers/net/wireless/realtek/rtl8xxxu/Kconfig      |   34 +
 drivers/net/wireless/realtek/rtl8xxxu/Makefile     |    1 +
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c   | 5976 ++++++++++++++++++++
 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h   |  676 +++
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h  |  981 ++++
 8 files changed, 7677 insertions(+)
 create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/Kconfig
 create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/Makefile
 create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
 create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
 create mode 100644 drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 9bf8683..e412601 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8877,6 +8877,13 @@ S:	Maintained
 F:	drivers/net/wireless/rtlwifi/
 F:	drivers/net/wireless/rtlwifi/rtl8192ce/
 
+RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
+M:	Jes Sorensen <Jes.Sorensen@redhat.com>
+L:	linux-wireless@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
+S:	Maintained
+F:	drivers/net/wireless/realtek/rtl8xxxu/
+
 S3 SAVAGE FRAMEBUFFER DRIVER
 M:	Antonino Daplas <adaplas@gmail.com>
 L:	linux-fbdev@vger.kernel.org
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 91907c4..f9f9422 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -279,6 +279,7 @@ source "drivers/net/wireless/p54/Kconfig"
 source "drivers/net/wireless/rt2x00/Kconfig"
 source "drivers/net/wireless/mediatek/Kconfig"
 source "drivers/net/wireless/realtek/rtlwifi/Kconfig"
+source "drivers/net/wireless/realtek/rtl8xxxu/Kconfig"
 source "drivers/net/wireless/ti/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
 source "drivers/net/wireless/mwifiex/Kconfig"
diff --git a/drivers/net/wireless/realtek/Makefile b/drivers/net/wireless/realtek/Makefile
index 3489b98..9c78deb 100644
--- a/drivers/net/wireless/realtek/Makefile
+++ b/drivers/net/wireless/realtek/Makefile
@@ -5,4 +5,5 @@
 obj-$(CONFIG_RTL8180)		+= rtl818x/
 obj-$(CONFIG_RTL8187)		+= rtl818x/
 obj-$(CONFIG_RTLWIFI)		+= rtlwifi/
+obj-$(CONFIG_RTL8XXXU)		+= rtl8xxxu/
 
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig
new file mode 100644
index 0000000..dd4d626
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtl8xxxu/Kconfig
@@ -0,0 +1,34 @@
+#
+# RTL8XXXU Wireless LAN device configuration
+#
+config RTL8XXXU
+	tristate "RTL8723AU/RTL8188[CR]U/RTL819[12]CU (mac80211) support"
+	depends on MAC80211 && USB
+	---help---
+	  This is an alternative driver for various Realtek RTL8XXX
+	  parts written to utilize the Linux mac80211 stack.
+	  The driver is known to work with a number of RTL8723AU,
+	  RL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU devices
+
+	  This driver is under development and has a limited feature
+	  set. In particular it does not yet support 40MHz channels
+	  and power management. However it should have a smaller
+	  memory footprint than the vendor drivers and benetifs
+	  from the in kernel mac80211 stack.
+
+	  It can coexist with drivers from drivers/staging/rtl8723au,
+	  drivers/staging/rtl8192u, and drivers/net/wireless/rtlwifi,
+	  but you will need to control which module you wish to load.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called r8xxxu.  If unsure, say N.
+
+config RTL8XXXU_UNTESTED
+	bool "Include support for untested Realtek 8xxx USB devices (EXPERIMENTAL)"
+	depends on RTL8XXXU
+	---help---
+	  This option enables detection of Realtek 8723/8188/8191/8192 WiFi
+	  USB devices which have not been tested directly by the driver
+	  author or reported to be working by third parties.
+
+	  Please report your results!
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/Makefile b/drivers/net/wireless/realtek/rtl8xxxu/Makefile
new file mode 100644
index 0000000..5dea3bb
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtl8xxxu/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_RTL8XXXU)	+= rtl8xxxu.o
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
new file mode 100644
index 0000000..47e52ad
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
@@ -0,0 +1,5976 @@
+/*
+ * RTL8XXXU mac80211 USB driver
+ *
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Portions, notably calibration code:
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This driver was written as a replacement for the vendor provided
+ * rtl8723au driver. As the Realtek 8xxx chips are very similar in
+ * their programming interface, I have started adding support for
+ * additional 8xxx chips like the 8192cu, 8188cus, etc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/moduleparam.h>
+#include <net/mac80211.h>
+#include "rtl8xxxu.h"
+#include "rtl8xxxu_regs.h"
+
+#define DRIVER_NAME "rtl8xxxu"
+
+static int rtl8xxxu_debug;
+static bool rtl8xxxu_ht40_2g;
+
+MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>");
+MODULE_DESCRIPTION("RTL8XXXu USB mac80211 Wireless LAN Driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aufw_B_NoBT.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_A.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_B.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8192cufw_TMSC.bin");
+
+module_param_named(debug, rtl8xxxu_debug, int, 0600);
+MODULE_PARM_DESC(debug, "Set debug mask");
+module_param_named(ht40_2g, rtl8xxxu_ht40_2g, bool, 0600);
+MODULE_PARM_DESC(ht40_2g, "Enable HT40 support on the 2.4GHz band");
+
+#define USB_VENDOR_ID_REALTEK		0x0bda
+/* Minimum IEEE80211_MAX_FRAME_LEN */
+#define RTL_RX_BUFFER_SIZE		IEEE80211_MAX_FRAME_LEN
+#define RTL8XXXU_RX_URBS		32
+#define RTL8XXXU_RX_URB_PENDING_WATER	8
+#define RTL8XXXU_TX_URBS		64
+#define RTL8XXXU_TX_URB_LOW_WATER	25
+#define RTL8XXXU_TX_URB_HIGH_WATER	32
+
+static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb);
+
+static struct ieee80211_rate rtl8xxxu_rates[] = {
+	{ .bitrate = 10, .hw_value = DESC_RATE_1M, .flags = 0 },
+	{ .bitrate = 20, .hw_value = DESC_RATE_2M, .flags = 0 },
+	{ .bitrate = 55, .hw_value = DESC_RATE_5_5M, .flags = 0 },
+	{ .bitrate = 110, .hw_value = DESC_RATE_11M, .flags = 0 },
+	{ .bitrate = 60, .hw_value = DESC_RATE_6M, .flags = 0 },
+	{ .bitrate = 90, .hw_value = DESC_RATE_9M, .flags = 0 },
+	{ .bitrate = 120, .hw_value = DESC_RATE_12M, .flags = 0 },
+	{ .bitrate = 180, .hw_value = DESC_RATE_18M, .flags = 0 },
+	{ .bitrate = 240, .hw_value = DESC_RATE_24M, .flags = 0 },
+	{ .bitrate = 360, .hw_value = DESC_RATE_36M, .flags = 0 },
+	{ .bitrate = 480, .hw_value = DESC_RATE_48M, .flags = 0 },
+	{ .bitrate = 540, .hw_value = DESC_RATE_54M, .flags = 0 },
+};
+
+static struct ieee80211_channel rtl8xxxu_channels_2g[] = {
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2412,
+	  .hw_value = 1, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2417,
+	  .hw_value = 2, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2422,
+	  .hw_value = 3, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2427,
+	  .hw_value = 4, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2432,
+	  .hw_value = 5, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2437,
+	  .hw_value = 6, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2442,
+	  .hw_value = 7, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2447,
+	  .hw_value = 8, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2452,
+	  .hw_value = 9, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2457,
+	  .hw_value = 10, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2462,
+	  .hw_value = 11, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2467,
+	  .hw_value = 12, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2472,
+	  .hw_value = 13, .max_power = 30 },
+	{ .band = IEEE80211_BAND_2GHZ, .center_freq = 2484,
+	  .hw_value = 14, .max_power = 30 }
+};
+
+static struct ieee80211_supported_band rtl8xxxu_supported_band = {
+	.channels = rtl8xxxu_channels_2g,
+	.n_channels = ARRAY_SIZE(rtl8xxxu_channels_2g),
+	.bitrates = rtl8xxxu_rates,
+	.n_bitrates = ARRAY_SIZE(rtl8xxxu_rates),
+};
+
+static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = {
+	{0x420, 0x80}, {0x423, 0x00}, {0x430, 0x00}, {0x431, 0x00},
+	{0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05},
+	{0x436, 0x06}, {0x437, 0x07}, {0x438, 0x00}, {0x439, 0x00},
+	{0x43a, 0x00}, {0x43b, 0x01}, {0x43c, 0x04}, {0x43d, 0x05},
+	{0x43e, 0x06}, {0x43f, 0x07}, {0x440, 0x5d}, {0x441, 0x01},
+	{0x442, 0x00}, {0x444, 0x15}, {0x445, 0xf0}, {0x446, 0x0f},
+	{0x447, 0x00}, {0x458, 0x41}, {0x459, 0xa8}, {0x45a, 0x72},
+	{0x45b, 0xb9}, {0x460, 0x66}, {0x461, 0x66}, {0x462, 0x08},
+	{0x463, 0x03}, {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff},
+	{0x4cd, 0xff}, {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2},
+	{0x502, 0x2f}, {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3},
+	{0x506, 0x5e}, {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4},
+	{0x50a, 0x5e}, {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4},
+	{0x50e, 0x00}, {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a},
+	{0x515, 0x10}, {0x516, 0x0a}, {0x517, 0x10}, {0x51a, 0x16},
+	{0x524, 0x0f}, {0x525, 0x4f}, {0x546, 0x40}, {0x547, 0x00},
+	{0x550, 0x10}, {0x551, 0x10}, {0x559, 0x02}, {0x55a, 0x02},
+	{0x55d, 0xff}, {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a},
+	{0x652, 0x20}, {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e},
+	{0x63f, 0x0e}, {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43},
+	{0x702, 0x65}, {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43},
+	{0x70a, 0x65}, {0x70b, 0x87}, {0xffff, 0xff},
+};
+
+static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = {
+	{0x800, 0x80040000}, {0x804, 0x00000003},
+	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+	{0x810, 0x10001331}, {0x814, 0x020c3d10},
+	{0x818, 0x02200385}, {0x81c, 0x00000000},
+	{0x820, 0x01000100}, {0x824, 0x00390004},
+	{0x828, 0x00000000}, {0x82c, 0x00000000},
+	{0x830, 0x00000000}, {0x834, 0x00000000},
+	{0x838, 0x00000000}, {0x83c, 0x00000000},
+	{0x840, 0x00010000}, {0x844, 0x00000000},
+	{0x848, 0x00000000}, {0x84c, 0x00000000},
+	{0x850, 0x00000000}, {0x854, 0x00000000},
+	{0x858, 0x569a569a}, {0x85c, 0x001b25a4},
+	{0x860, 0x66f60110}, {0x864, 0x061f0130},
+	{0x868, 0x00000000}, {0x86c, 0x32323200},
+	{0x870, 0x07000760}, {0x874, 0x22004000},
+	{0x878, 0x00000808}, {0x87c, 0x00000000},
+	{0x880, 0xc0083070}, {0x884, 0x000004d5},
+	{0x888, 0x00000000}, {0x88c, 0xccc000c0},
+	{0x890, 0x00000800}, {0x894, 0xfffffffe},
+	{0x898, 0x40302010}, {0x89c, 0x00706050},
+	{0x900, 0x00000000}, {0x904, 0x00000023},
+	{0x908, 0x00000000}, {0x90c, 0x81121111},
+	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
+	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
+	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
+	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
+	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
+	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
+	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
+	{0xa78, 0x00000900},
+	{0xc00, 0x48071d40}, {0xc04, 0x03a05611},
+	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
+	{0xc10, 0x08800000}, {0xc14, 0x40000100},
+	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
+	{0xc20, 0x00000000}, {0xc24, 0x00000000},
+	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
+	{0xc30, 0x69e9ac44}, {0xc34, 0x469652af},
+	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
+	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
+	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
+	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
+	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
+	{0xc60, 0x00000000}, {0xc64, 0x7112848b},
+	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
+	{0xc70, 0x2c7f000d}, {0xc74, 0x018610db},
+	{0xc78, 0x0000001f}, {0xc7c, 0x00b91612},
+	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
+	{0xc88, 0x40000100}, {0xc8c, 0x20200000},
+	{0xc90, 0x00121820}, {0xc94, 0x00000000},
+	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
+	{0xca0, 0x00000000}, {0xca4, 0x00000080},
+	{0xca8, 0x00000000}, {0xcac, 0x00000000},
+	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
+	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
+	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
+	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
+	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
+	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
+	{0xce0, 0x00222222}, {0xce4, 0x00000000},
+	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
+	{0xd00, 0x00080740}, {0xd04, 0x00020401},
+	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
+	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
+	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
+	{0xd30, 0x00000000}, {0xd34, 0x80608000},
+	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
+	{0xd40, 0x00000000}, {0xd44, 0x00000000},
+	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
+	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
+	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
+	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
+	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
+	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
+	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
+	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
+	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
+	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
+	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
+	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
+	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
+	{0xe5c, 0x28160d05}, {0xe60, 0x00000008},
+	{0xe68, 0x001b25a4}, {0xe6c, 0x631b25a0},
+	{0xe70, 0x631b25a0}, {0xe74, 0x081b25a0},
+	{0xe78, 0x081b25a0}, {0xe7c, 0x081b25a0},
+	{0xe80, 0x081b25a0}, {0xe84, 0x631b25a0},
+	{0xe88, 0x081b25a0}, {0xe8c, 0x631b25a0},
+	{0xed0, 0x631b25a0}, {0xed4, 0x631b25a0},
+	{0xed8, 0x631b25a0}, {0xedc, 0x001b25a0},
+	{0xee0, 0x001b25a0}, {0xeec, 0x6b1b25a0},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8192cu_phy_2t_init_table[] = {
+	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
+	{0x800, 0x80040002}, {0x804, 0x00000003},
+	{0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+	{0x810, 0x10000330}, {0x814, 0x020c3d10},
+	{0x818, 0x02200385}, {0x81c, 0x00000000},
+	{0x820, 0x01000100}, {0x824, 0x00390004},
+	{0x828, 0x01000100}, {0x82c, 0x00390004},
+	{0x830, 0x27272727}, {0x834, 0x27272727},
+	{0x838, 0x27272727}, {0x83c, 0x27272727},
+	{0x840, 0x00010000}, {0x844, 0x00010000},
+	{0x848, 0x27272727}, {0x84c, 0x27272727},
+	{0x850, 0x00000000}, {0x854, 0x00000000},
+	{0x858, 0x569a569a}, {0x85c, 0x0c1b25a4},
+	{0x860, 0x66e60230}, {0x864, 0x061f0130},
+	{0x868, 0x27272727}, {0x86c, 0x2b2b2b27},
+	{0x870, 0x07000700}, {0x874, 0x22184000},
+	{0x878, 0x08080808}, {0x87c, 0x00000000},
+	{0x880, 0xc0083070}, {0x884, 0x000004d5},
+	{0x888, 0x00000000}, {0x88c, 0xcc0000c0},
+	{0x890, 0x00000800}, {0x894, 0xfffffffe},
+	{0x898, 0x40302010}, {0x89c, 0x00706050},
+	{0x900, 0x00000000}, {0x904, 0x00000023},
+	{0x908, 0x00000000}, {0x90c, 0x81121313},
+	{0xa00, 0x00d047c8}, {0xa04, 0x80ff000c},
+	{0xa08, 0x8c838300}, {0xa0c, 0x2e68120f},
+	{0xa10, 0x9500bb78}, {0xa14, 0x11144028},
+	{0xa18, 0x00881117}, {0xa1c, 0x89140f00},
+	{0xa20, 0x1a1b0000}, {0xa24, 0x090e1317},
+	{0xa28, 0x00000204}, {0xa2c, 0x00d30000},
+	{0xa70, 0x101fbf00}, {0xa74, 0x00000007},
+	{0xc00, 0x48071d40}, {0xc04, 0x03a05633},
+	{0xc08, 0x000000e4}, {0xc0c, 0x6c6c6c6c},
+	{0xc10, 0x08800000}, {0xc14, 0x40000100},
+	{0xc18, 0x08800000}, {0xc1c, 0x40000100},
+	{0xc20, 0x00000000}, {0xc24, 0x00000000},
+	{0xc28, 0x00000000}, {0xc2c, 0x00000000},
+	{0xc30, 0x69e9ac44}, {0xc34, 0x469652cf},
+	{0xc38, 0x49795994}, {0xc3c, 0x0a97971c},
+	{0xc40, 0x1f7c403f}, {0xc44, 0x000100b7},
+	{0xc48, 0xec020107}, {0xc4c, 0x007f037f},
+	{0xc50, 0x69543420}, {0xc54, 0x43bc0094},
+	{0xc58, 0x69543420}, {0xc5c, 0x433c0094},
+	{0xc60, 0x00000000}, {0xc64, 0x5116848b},
+	{0xc68, 0x47c00bff}, {0xc6c, 0x00000036},
+	{0xc70, 0x2c7f000d}, {0xc74, 0x2186115b},
+	{0xc78, 0x0000001f}, {0xc7c, 0x00b99612},
+	{0xc80, 0x40000100}, {0xc84, 0x20f60000},
+	{0xc88, 0x40000100}, {0xc8c, 0xa0e40000},
+	{0xc90, 0x00121820}, {0xc94, 0x00000000},
+	{0xc98, 0x00121820}, {0xc9c, 0x00007f7f},
+	{0xca0, 0x00000000}, {0xca4, 0x00000080},
+	{0xca8, 0x00000000}, {0xcac, 0x00000000},
+	{0xcb0, 0x00000000}, {0xcb4, 0x00000000},
+	{0xcb8, 0x00000000}, {0xcbc, 0x28000000},
+	{0xcc0, 0x00000000}, {0xcc4, 0x00000000},
+	{0xcc8, 0x00000000}, {0xccc, 0x00000000},
+	{0xcd0, 0x00000000}, {0xcd4, 0x00000000},
+	{0xcd8, 0x64b22427}, {0xcdc, 0x00766932},
+	{0xce0, 0x00222222}, {0xce4, 0x00000000},
+	{0xce8, 0x37644302}, {0xcec, 0x2f97d40c},
+	{0xd00, 0x00080740}, {0xd04, 0x00020403},
+	{0xd08, 0x0000907f}, {0xd0c, 0x20010201},
+	{0xd10, 0xa0633333}, {0xd14, 0x3333bc43},
+	{0xd18, 0x7a8f5b6b}, {0xd2c, 0xcc979975},
+	{0xd30, 0x00000000}, {0xd34, 0x80608000},
+	{0xd38, 0x00000000}, {0xd3c, 0x00027293},
+	{0xd40, 0x00000000}, {0xd44, 0x00000000},
+	{0xd48, 0x00000000}, {0xd4c, 0x00000000},
+	{0xd50, 0x6437140a}, {0xd54, 0x00000000},
+	{0xd58, 0x00000000}, {0xd5c, 0x30032064},
+	{0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+	{0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+	{0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+	{0xd78, 0x000e3c24}, {0xe00, 0x2a2a2a2a},
+	{0xe04, 0x2a2a2a2a}, {0xe08, 0x03902a2a},
+	{0xe10, 0x2a2a2a2a}, {0xe14, 0x2a2a2a2a},
+	{0xe18, 0x2a2a2a2a}, {0xe1c, 0x2a2a2a2a},
+	{0xe28, 0x00000000}, {0xe30, 0x1000dc1f},
+	{0xe34, 0x10008c1f}, {0xe38, 0x02140102},
+	{0xe3c, 0x681604c2}, {0xe40, 0x01007c00},
+	{0xe44, 0x01004800}, {0xe48, 0xfb000000},
+	{0xe4c, 0x000028d1}, {0xe50, 0x1000dc1f},
+	{0xe54, 0x10008c1f}, {0xe58, 0x02140102},
+	{0xe5c, 0x28160d05}, {0xe60, 0x00000010},
+	{0xe68, 0x001b25a4}, {0xe6c, 0x63db25a4},
+	{0xe70, 0x63db25a4}, {0xe74, 0x0c1b25a4},
+	{0xe78, 0x0c1b25a4}, {0xe7c, 0x0c1b25a4},
+	{0xe80, 0x0c1b25a4}, {0xe84, 0x63db25a4},
+	{0xe88, 0x0c1b25a4}, {0xe8c, 0x63db25a4},
+	{0xed0, 0x63db25a4}, {0xed4, 0x63db25a4},
+	{0xed8, 0x63db25a4}, {0xedc, 0x001b25a4},
+	{0xee0, 0x001b25a4}, {0xeec, 0x6fdb25a4},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8188ru_phy_1t_highpa_table[] = {
+	{0x024, 0x0011800f}, {0x028, 0x00ffdb83},
+	{0x040, 0x000c0004}, {0x800, 0x80040000},
+	{0x804, 0x00000001}, {0x808, 0x0000fc00},
+	{0x80c, 0x0000000a}, {0x810, 0x10005388},
+	{0x814, 0x020c3d10}, {0x818, 0x02200385},
+	{0x81c, 0x00000000}, {0x820, 0x01000100},
+	{0x824, 0x00390204}, {0x828, 0x00000000},
+	{0x82c, 0x00000000}, {0x830, 0x00000000},
+	{0x834, 0x00000000}, {0x838, 0x00000000},
+	{0x83c, 0x00000000}, {0x840, 0x00010000},
+	{0x844, 0x00000000}, {0x848, 0x00000000},
+	{0x84c, 0x00000000}, {0x850, 0x00000000},
+	{0x854, 0x00000000}, {0x858, 0x569a569a},
+	{0x85c, 0x001b25a4}, {0x860, 0x66e60230},
+	{0x864, 0x061f0130}, {0x868, 0x00000000},
+	{0x86c, 0x20202000}, {0x870, 0x03000300},
+	{0x874, 0x22004000}, {0x878, 0x00000808},
+	{0x87c, 0x00ffc3f1}, {0x880, 0xc0083070},
+	{0x884, 0x000004d5}, {0x888, 0x00000000},
+	{0x88c, 0xccc000c0}, {0x890, 0x00000800},
+	{0x894, 0xfffffffe}, {0x898, 0x40302010},
+	{0x89c, 0x00706050}, {0x900, 0x00000000},
+	{0x904, 0x00000023}, {0x908, 0x00000000},
+	{0x90c, 0x81121111}, {0xa00, 0x00d047c8},
+	{0xa04, 0x80ff000c}, {0xa08, 0x8c838300},
+	{0xa0c, 0x2e68120f}, {0xa10, 0x9500bb78},
+	{0xa14, 0x11144028}, {0xa18, 0x00881117},
+	{0xa1c, 0x89140f00}, {0xa20, 0x15160000},
+	{0xa24, 0x070b0f12}, {0xa28, 0x00000104},
+	{0xa2c, 0x00d30000}, {0xa70, 0x101fbf00},
+	{0xa74, 0x00000007}, {0xc00, 0x48071d40},
+	{0xc04, 0x03a05611}, {0xc08, 0x000000e4},
+	{0xc0c, 0x6c6c6c6c}, {0xc10, 0x08800000},
+	{0xc14, 0x40000100}, {0xc18, 0x08800000},
+	{0xc1c, 0x40000100}, {0xc20, 0x00000000},
+	{0xc24, 0x00000000}, {0xc28, 0x00000000},
+	{0xc2c, 0x00000000}, {0xc30, 0x69e9ac44},
+	{0xc34, 0x469652cf}, {0xc38, 0x49795994},
+	{0xc3c, 0x0a97971c}, {0xc40, 0x1f7c403f},
+	{0xc44, 0x000100b7}, {0xc48, 0xec020107},
+	{0xc4c, 0x007f037f}, {0xc50, 0x6954342e},
+	{0xc54, 0x43bc0094}, {0xc58, 0x6954342f},
+	{0xc5c, 0x433c0094}, {0xc60, 0x00000000},
+	{0xc64, 0x5116848b}, {0xc68, 0x47c00bff},
+	{0xc6c, 0x00000036}, {0xc70, 0x2c46000d},
+	{0xc74, 0x018610db}, {0xc78, 0x0000001f},
+	{0xc7c, 0x00b91612}, {0xc80, 0x24000090},
+	{0xc84, 0x20f60000}, {0xc88, 0x24000090},
+	{0xc8c, 0x20200000}, {0xc90, 0x00121820},
+	{0xc94, 0x00000000}, {0xc98, 0x00121820},
+	{0xc9c, 0x00007f7f}, {0xca0, 0x00000000},
+	{0xca4, 0x00000080}, {0xca8, 0x00000000},
+	{0xcac, 0x00000000}, {0xcb0, 0x00000000},
+	{0xcb4, 0x00000000}, {0xcb8, 0x00000000},
+	{0xcbc, 0x28000000}, {0xcc0, 0x00000000},
+	{0xcc4, 0x00000000}, {0xcc8, 0x00000000},
+	{0xccc, 0x00000000}, {0xcd0, 0x00000000},
+	{0xcd4, 0x00000000}, {0xcd8, 0x64b22427},
+	{0xcdc, 0x00766932}, {0xce0, 0x00222222},
+	{0xce4, 0x00000000}, {0xce8, 0x37644302},
+	{0xcec, 0x2f97d40c}, {0xd00, 0x00080740},
+	{0xd04, 0x00020401}, {0xd08, 0x0000907f},
+	{0xd0c, 0x20010201}, {0xd10, 0xa0633333},
+	{0xd14, 0x3333bc43}, {0xd18, 0x7a8f5b6b},
+	{0xd2c, 0xcc979975}, {0xd30, 0x00000000},
+	{0xd34, 0x80608000}, {0xd38, 0x00000000},
+	{0xd3c, 0x00027293}, {0xd40, 0x00000000},
+	{0xd44, 0x00000000}, {0xd48, 0x00000000},
+	{0xd4c, 0x00000000}, {0xd50, 0x6437140a},
+	{0xd54, 0x00000000}, {0xd58, 0x00000000},
+	{0xd5c, 0x30032064}, {0xd60, 0x4653de68},
+	{0xd64, 0x04518a3c}, {0xd68, 0x00002101},
+	{0xd6c, 0x2a201c16}, {0xd70, 0x1812362e},
+	{0xd74, 0x322c2220}, {0xd78, 0x000e3c24},
+	{0xe00, 0x24242424}, {0xe04, 0x24242424},
+	{0xe08, 0x03902024}, {0xe10, 0x24242424},
+	{0xe14, 0x24242424}, {0xe18, 0x24242424},
+	{0xe1c, 0x24242424}, {0xe28, 0x00000000},
+	{0xe30, 0x1000dc1f}, {0xe34, 0x10008c1f},
+	{0xe38, 0x02140102}, {0xe3c, 0x681604c2},
+	{0xe40, 0x01007c00}, {0xe44, 0x01004800},
+	{0xe48, 0xfb000000}, {0xe4c, 0x000028d1},
+	{0xe50, 0x1000dc1f}, {0xe54, 0x10008c1f},
+	{0xe58, 0x02140102}, {0xe5c, 0x28160d05},
+	{0xe60, 0x00000008}, {0xe68, 0x001b25a4},
+	{0xe6c, 0x631b25a0}, {0xe70, 0x631b25a0},
+	{0xe74, 0x081b25a0}, {0xe78, 0x081b25a0},
+	{0xe7c, 0x081b25a0}, {0xe80, 0x081b25a0},
+	{0xe84, 0x631b25a0}, {0xe88, 0x081b25a0},
+	{0xe8c, 0x631b25a0}, {0xed0, 0x631b25a0},
+	{0xed4, 0x631b25a0}, {0xed8, 0x631b25a0},
+	{0xedc, 0x001b25a0}, {0xee0, 0x001b25a0},
+	{0xeec, 0x6b1b25a0}, {0xee8, 0x31555448},
+	{0xf14, 0x00000003}, {0xf4c, 0x00000000},
+	{0xf00, 0x00000300},
+	{0xffff, 0xffffffff},
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_standard_table[] = {
+	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
+	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
+	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
+	{0xc78, 0x7a060001}, {0xc78, 0x79070001},
+	{0xc78, 0x78080001}, {0xc78, 0x77090001},
+	{0xc78, 0x760a0001}, {0xc78, 0x750b0001},
+	{0xc78, 0x740c0001}, {0xc78, 0x730d0001},
+	{0xc78, 0x720e0001}, {0xc78, 0x710f0001},
+	{0xc78, 0x70100001}, {0xc78, 0x6f110001},
+	{0xc78, 0x6e120001}, {0xc78, 0x6d130001},
+	{0xc78, 0x6c140001}, {0xc78, 0x6b150001},
+	{0xc78, 0x6a160001}, {0xc78, 0x69170001},
+	{0xc78, 0x68180001}, {0xc78, 0x67190001},
+	{0xc78, 0x661a0001}, {0xc78, 0x651b0001},
+	{0xc78, 0x641c0001}, {0xc78, 0x631d0001},
+	{0xc78, 0x621e0001}, {0xc78, 0x611f0001},
+	{0xc78, 0x60200001}, {0xc78, 0x49210001},
+	{0xc78, 0x48220001}, {0xc78, 0x47230001},
+	{0xc78, 0x46240001}, {0xc78, 0x45250001},
+	{0xc78, 0x44260001}, {0xc78, 0x43270001},
+	{0xc78, 0x42280001}, {0xc78, 0x41290001},
+	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
+	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
+	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
+	{0xc78, 0x21300001}, {0xc78, 0x20310001},
+	{0xc78, 0x06320001}, {0xc78, 0x05330001},
+	{0xc78, 0x04340001}, {0xc78, 0x03350001},
+	{0xc78, 0x02360001}, {0xc78, 0x01370001},
+	{0xc78, 0x00380001}, {0xc78, 0x00390001},
+	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
+	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
+	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
+	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
+	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
+	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
+	{0xc78, 0x7a460001}, {0xc78, 0x79470001},
+	{0xc78, 0x78480001}, {0xc78, 0x77490001},
+	{0xc78, 0x764a0001}, {0xc78, 0x754b0001},
+	{0xc78, 0x744c0001}, {0xc78, 0x734d0001},
+	{0xc78, 0x724e0001}, {0xc78, 0x714f0001},
+	{0xc78, 0x70500001}, {0xc78, 0x6f510001},
+	{0xc78, 0x6e520001}, {0xc78, 0x6d530001},
+	{0xc78, 0x6c540001}, {0xc78, 0x6b550001},
+	{0xc78, 0x6a560001}, {0xc78, 0x69570001},
+	{0xc78, 0x68580001}, {0xc78, 0x67590001},
+	{0xc78, 0x665a0001}, {0xc78, 0x655b0001},
+	{0xc78, 0x645c0001}, {0xc78, 0x635d0001},
+	{0xc78, 0x625e0001}, {0xc78, 0x615f0001},
+	{0xc78, 0x60600001}, {0xc78, 0x49610001},
+	{0xc78, 0x48620001}, {0xc78, 0x47630001},
+	{0xc78, 0x46640001}, {0xc78, 0x45650001},
+	{0xc78, 0x44660001}, {0xc78, 0x43670001},
+	{0xc78, 0x42680001}, {0xc78, 0x41690001},
+	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
+	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
+	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
+	{0xc78, 0x21700001}, {0xc78, 0x20710001},
+	{0xc78, 0x06720001}, {0xc78, 0x05730001},
+	{0xc78, 0x04740001}, {0xc78, 0x03750001},
+	{0xc78, 0x02760001}, {0xc78, 0x01770001},
+	{0xc78, 0x00780001}, {0xc78, 0x00790001},
+	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
+	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
+	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
+	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
+	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
+	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
+	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
+	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
+	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
+	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
+	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
+	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
+	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
+	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
+	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
+	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
+	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
+	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
+	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
+	{0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_highpa_table[] = {
+	{0xc78, 0x7b000001}, {0xc78, 0x7b010001},
+	{0xc78, 0x7b020001}, {0xc78, 0x7b030001},
+	{0xc78, 0x7b040001}, {0xc78, 0x7b050001},
+	{0xc78, 0x7b060001}, {0xc78, 0x7b070001},
+	{0xc78, 0x7b080001}, {0xc78, 0x7a090001},
+	{0xc78, 0x790a0001}, {0xc78, 0x780b0001},
+	{0xc78, 0x770c0001}, {0xc78, 0x760d0001},
+	{0xc78, 0x750e0001}, {0xc78, 0x740f0001},
+	{0xc78, 0x73100001}, {0xc78, 0x72110001},
+	{0xc78, 0x71120001}, {0xc78, 0x70130001},
+	{0xc78, 0x6f140001}, {0xc78, 0x6e150001},
+	{0xc78, 0x6d160001}, {0xc78, 0x6c170001},
+	{0xc78, 0x6b180001}, {0xc78, 0x6a190001},
+	{0xc78, 0x691a0001}, {0xc78, 0x681b0001},
+	{0xc78, 0x671c0001}, {0xc78, 0x661d0001},
+	{0xc78, 0x651e0001}, {0xc78, 0x641f0001},
+	{0xc78, 0x63200001}, {0xc78, 0x62210001},
+	{0xc78, 0x61220001}, {0xc78, 0x60230001},
+	{0xc78, 0x46240001}, {0xc78, 0x45250001},
+	{0xc78, 0x44260001}, {0xc78, 0x43270001},
+	{0xc78, 0x42280001}, {0xc78, 0x41290001},
+	{0xc78, 0x402a0001}, {0xc78, 0x262b0001},
+	{0xc78, 0x252c0001}, {0xc78, 0x242d0001},
+	{0xc78, 0x232e0001}, {0xc78, 0x222f0001},
+	{0xc78, 0x21300001}, {0xc78, 0x20310001},
+	{0xc78, 0x06320001}, {0xc78, 0x05330001},
+	{0xc78, 0x04340001}, {0xc78, 0x03350001},
+	{0xc78, 0x02360001}, {0xc78, 0x01370001},
+	{0xc78, 0x00380001}, {0xc78, 0x00390001},
+	{0xc78, 0x003a0001}, {0xc78, 0x003b0001},
+	{0xc78, 0x003c0001}, {0xc78, 0x003d0001},
+	{0xc78, 0x003e0001}, {0xc78, 0x003f0001},
+	{0xc78, 0x7b400001}, {0xc78, 0x7b410001},
+	{0xc78, 0x7b420001}, {0xc78, 0x7b430001},
+	{0xc78, 0x7b440001}, {0xc78, 0x7b450001},
+	{0xc78, 0x7b460001}, {0xc78, 0x7b470001},
+	{0xc78, 0x7b480001}, {0xc78, 0x7a490001},
+	{0xc78, 0x794a0001}, {0xc78, 0x784b0001},
+	{0xc78, 0x774c0001}, {0xc78, 0x764d0001},
+	{0xc78, 0x754e0001}, {0xc78, 0x744f0001},
+	{0xc78, 0x73500001}, {0xc78, 0x72510001},
+	{0xc78, 0x71520001}, {0xc78, 0x70530001},
+	{0xc78, 0x6f540001}, {0xc78, 0x6e550001},
+	{0xc78, 0x6d560001}, {0xc78, 0x6c570001},
+	{0xc78, 0x6b580001}, {0xc78, 0x6a590001},
+	{0xc78, 0x695a0001}, {0xc78, 0x685b0001},
+	{0xc78, 0x675c0001}, {0xc78, 0x665d0001},
+	{0xc78, 0x655e0001}, {0xc78, 0x645f0001},
+	{0xc78, 0x63600001}, {0xc78, 0x62610001},
+	{0xc78, 0x61620001}, {0xc78, 0x60630001},
+	{0xc78, 0x46640001}, {0xc78, 0x45650001},
+	{0xc78, 0x44660001}, {0xc78, 0x43670001},
+	{0xc78, 0x42680001}, {0xc78, 0x41690001},
+	{0xc78, 0x406a0001}, {0xc78, 0x266b0001},
+	{0xc78, 0x256c0001}, {0xc78, 0x246d0001},
+	{0xc78, 0x236e0001}, {0xc78, 0x226f0001},
+	{0xc78, 0x21700001}, {0xc78, 0x20710001},
+	{0xc78, 0x06720001}, {0xc78, 0x05730001},
+	{0xc78, 0x04740001}, {0xc78, 0x03750001},
+	{0xc78, 0x02760001}, {0xc78, 0x01770001},
+	{0xc78, 0x00780001}, {0xc78, 0x00790001},
+	{0xc78, 0x007a0001}, {0xc78, 0x007b0001},
+	{0xc78, 0x007c0001}, {0xc78, 0x007d0001},
+	{0xc78, 0x007e0001}, {0xc78, 0x007f0001},
+	{0xc78, 0x3800001e}, {0xc78, 0x3801001e},
+	{0xc78, 0x3802001e}, {0xc78, 0x3803001e},
+	{0xc78, 0x3804001e}, {0xc78, 0x3805001e},
+	{0xc78, 0x3806001e}, {0xc78, 0x3807001e},
+	{0xc78, 0x3808001e}, {0xc78, 0x3c09001e},
+	{0xc78, 0x3e0a001e}, {0xc78, 0x400b001e},
+	{0xc78, 0x440c001e}, {0xc78, 0x480d001e},
+	{0xc78, 0x4c0e001e}, {0xc78, 0x500f001e},
+	{0xc78, 0x5210001e}, {0xc78, 0x5611001e},
+	{0xc78, 0x5a12001e}, {0xc78, 0x5e13001e},
+	{0xc78, 0x6014001e}, {0xc78, 0x6015001e},
+	{0xc78, 0x6016001e}, {0xc78, 0x6217001e},
+	{0xc78, 0x6218001e}, {0xc78, 0x6219001e},
+	{0xc78, 0x621a001e}, {0xc78, 0x621b001e},
+	{0xc78, 0x621c001e}, {0xc78, 0x621d001e},
+	{0xc78, 0x621e001e}, {0xc78, 0x621f001e},
+	{0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00039c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001a3f1}, {0x0b, 0x00014787},
+	{0x0c, 0x000896fe}, {0x0d, 0x0000e02c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00030355},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0000024f},
+	{0x1f, 0x00000000}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x00057730},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f474},
+	{0x15, 0x0004f477}, {0x15, 0x0008f455},
+	{0x15, 0x000cf455}, {0x16, 0x00000339},
+	{0x16, 0x00040339}, {0x16, 0x00080339},
+	{0x16, 0x000c0366}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00000003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00000247}, {0x1f, 0x00000000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00010255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f424},
+	{0x15, 0x0004f424}, {0x15, 0x0008f424},
+	{0x15, 0x000cf424}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radiob_2t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287af}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x00014297},
+	{0x13, 0x00010295}, {0x13, 0x0000c298},
+	{0x13, 0x0000819c}, {0x13, 0x000040a8},
+	{0x13, 0x0000001c}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f424},
+	{0x15, 0x0004f424}, {0x15, 0x0008f424},
+	{0x15, 0x000cf424}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192cu_radioa_1t_init_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb1}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e52c},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00010255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x00000000},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000577c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x00032000}, {0x12, 0x00071000},
+	{0x12, 0x000b0000}, {0x12, 0x000fc000},
+	{0x13, 0x000287b3}, {0x13, 0x000244b7},
+	{0x13, 0x000204ab}, {0x13, 0x0001c49f},
+	{0x13, 0x00018493}, {0x13, 0x0001429b},
+	{0x13, 0x00010299}, {0x13, 0x0000c29c},
+	{0x13, 0x000081a0}, {0x13, 0x000040ac},
+	{0x13, 0x00000020}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f405},
+	{0x15, 0x0004f405}, {0x15, 0x0008f405},
+	{0x15, 0x000cf405}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = {
+	{0x00, 0x00030159}, {0x01, 0x00031284},
+	{0x02, 0x00098000}, {0x03, 0x00018c63},
+	{0x04, 0x000210e7}, {0x09, 0x0002044f},
+	{0x0a, 0x0001adb0}, {0x0b, 0x00054867},
+	{0x0c, 0x0008992e}, {0x0d, 0x0000e529},
+	{0x0e, 0x00039ce7}, {0x0f, 0x00000451},
+	{0x19, 0x00000000}, {0x1a, 0x00000255},
+	{0x1b, 0x00060a00}, {0x1c, 0x000fc378},
+	{0x1d, 0x000a1250}, {0x1e, 0x0004445f},
+	{0x1f, 0x00080001}, {0x20, 0x0000b614},
+	{0x21, 0x0006c000}, {0x22, 0x0000083c},
+	{0x23, 0x00001558}, {0x24, 0x00000060},
+	{0x25, 0x00000483}, {0x26, 0x0004f000},
+	{0x27, 0x000ec7d9}, {0x28, 0x000977c0},
+	{0x29, 0x00004783}, {0x2a, 0x00000001},
+	{0x2b, 0x00021334}, {0x2a, 0x00000000},
+	{0x2b, 0x00000054}, {0x2a, 0x00000001},
+	{0x2b, 0x00000808}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000c}, {0x2a, 0x00000002},
+	{0x2b, 0x00000808}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000003},
+	{0x2b, 0x00000808}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000004},
+	{0x2b, 0x00000808}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000005},
+	{0x2b, 0x00000808}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000006},
+	{0x2b, 0x00000709}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000007},
+	{0x2b, 0x00000709}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000008},
+	{0x2b, 0x0000060a}, {0x2b, 0x0004b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x00000009},
+	{0x2b, 0x0000060a}, {0x2b, 0x00053333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000a},
+	{0x2b, 0x0000060a}, {0x2b, 0x0005b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000b},
+	{0x2b, 0x0000060a}, {0x2b, 0x00063333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000c},
+	{0x2b, 0x0000060a}, {0x2b, 0x0006b333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000d},
+	{0x2b, 0x0000060a}, {0x2b, 0x00073333},
+	{0x2c, 0x0000000d}, {0x2a, 0x0000000e},
+	{0x2b, 0x0000050b}, {0x2b, 0x00066666},
+	{0x2c, 0x0000001a}, {0x2a, 0x000e0000},
+	{0x10, 0x0004000f}, {0x11, 0x000e31fc},
+	{0x10, 0x0006000f}, {0x11, 0x000ff9f8},
+	{0x10, 0x0002000f}, {0x11, 0x000203f9},
+	{0x10, 0x0003000f}, {0x11, 0x000ff500},
+	{0x10, 0x00000000}, {0x11, 0x00000000},
+	{0x10, 0x0008000f}, {0x11, 0x0003f100},
+	{0x10, 0x0009000f}, {0x11, 0x00023100},
+	{0x12, 0x000d8000}, {0x12, 0x00090000},
+	{0x12, 0x00051000}, {0x12, 0x00012000},
+	{0x13, 0x00028fb4}, {0x13, 0x00024fa8},
+	{0x13, 0x000207a4}, {0x13, 0x0001c3b0},
+	{0x13, 0x000183a4}, {0x13, 0x00014398},
+	{0x13, 0x000101a4}, {0x13, 0x0000c198},
+	{0x13, 0x000080a4}, {0x13, 0x00004098},
+	{0x13, 0x00000000}, {0x14, 0x0001944c},
+	{0x14, 0x00059444}, {0x14, 0x0009944c},
+	{0x14, 0x000d9444}, {0x15, 0x0000f405},
+	{0x15, 0x0004f405}, {0x15, 0x0008f405},
+	{0x15, 0x000cf405}, {0x16, 0x000e0330},
+	{0x16, 0x000a0330}, {0x16, 0x00060330},
+	{0x16, 0x00020330}, {0x00, 0x00010159},
+	{0x18, 0x0000f401}, {0xfe, 0x00000000},
+	{0xfe, 0x00000000}, {0x1f, 0x00080003},
+	{0xfe, 0x00000000}, {0xfe, 0x00000000},
+	{0x1e, 0x00044457}, {0x1f, 0x00080000},
+	{0x00, 0x00030159},
+	{0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = {
+	{	/* RF_A */
+		.hssiparm1 = REG_FPGA0_XA_HSSI_PARM1,
+		.hssiparm2 = REG_FPGA0_XA_HSSI_PARM2,
+		.lssiparm = REG_FPGA0_XA_LSSI_PARM,
+		.hspiread = REG_HSPI_XA_READBACK,
+		.lssiread = REG_FPGA0_XA_LSSI_READBACK,
+		.rf_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL,
+	},
+	{	/* RF_B */
+		.hssiparm1 = REG_FPGA0_XB_HSSI_PARM1,
+		.hssiparm2 = REG_FPGA0_XB_HSSI_PARM2,
+		.lssiparm = REG_FPGA0_XB_LSSI_PARM,
+		.hspiread = REG_HSPI_XB_READBACK,
+		.lssiread = REG_FPGA0_XB_LSSI_READBACK,
+		.rf_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL,
+	},
+};
+
+static const u32 rtl8723au_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = {
+	REG_OFDM0_XA_RX_IQ_IMBALANCE,
+	REG_OFDM0_XB_RX_IQ_IMBALANCE,
+	REG_OFDM0_ENERGY_CCA_THRES,
+	REG_OFDM0_AGCR_SSI_TABLE,
+	REG_OFDM0_XA_TX_IQ_IMBALANCE,
+	REG_OFDM0_XB_TX_IQ_IMBALANCE,
+	REG_OFDM0_XC_TX_AFE,
+	REG_OFDM0_XD_TX_AFE,
+	REG_OFDM0_RX_IQ_EXT_ANTA
+};
+
+static u8 rtl8xxxu_read8(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u8 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = priv->usb_buf.val8;
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)   = 0x%02x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static u16 rtl8xxxu_read16(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u16 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = le16_to_cpu(priv->usb_buf.val16);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)  = 0x%04x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static u32 rtl8xxxu_read32(struct rtl8xxxu_priv *priv, u16 addr)
+{
+	struct usb_device *udev = priv->udev;
+	int len;
+	u32 data;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	len = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_READ,
+			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	data = le32_to_cpu(priv->usb_buf.val32);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_READ)
+		dev_info(&udev->dev, "%s(%04x)  = 0x%08x, len %i\n",
+			 __func__, addr, data, len);
+	return data;
+}
+
+static int rtl8xxxu_write8(struct rtl8xxxu_priv *priv, u16 addr, u8 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val8 = val;
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val8, sizeof(u8),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%02x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int rtl8xxxu_write16(struct rtl8xxxu_priv *priv, u16 addr, u16 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val16 = cpu_to_le16(val);
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val16, sizeof(u16),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%04x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int rtl8xxxu_write32(struct rtl8xxxu_priv *priv, u16 addr, u32 val)
+{
+	struct usb_device *udev = priv->udev;
+	int ret;
+
+	mutex_lock(&priv->usb_buf_mutex);
+	priv->usb_buf.val32 = cpu_to_le32(val);
+	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+			      addr, 0, &priv->usb_buf.val32, sizeof(u32),
+			      RTW_USB_CONTROL_MSG_TIMEOUT);
+	mutex_unlock(&priv->usb_buf_mutex);
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_REG_WRITE)
+		dev_info(&udev->dev, "%s(%04x) = 0x%08x\n",
+			 __func__, addr, val);
+	return ret;
+}
+
+static int
+rtl8xxxu_writeN(struct rtl8xxxu_priv *priv, u16 addr, u8 *buf, u16 len)
+{
+	struct usb_device *udev = priv->udev;
+	int blocksize = priv->fops->writeN_block_size;
+	int ret, i, count, remainder;
+
+	count = len / blocksize;
+	remainder = len % blocksize;
+
+	for (i = 0; i < count; i++) {
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+				      addr, 0, buf, blocksize,
+				      RTW_USB_CONTROL_MSG_TIMEOUT);
+		if (ret != blocksize)
+			goto write_error;
+
+		addr += blocksize;
+		buf += blocksize;
+	}
+
+	if (remainder) {
+		ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				      REALTEK_USB_CMD_REQ, REALTEK_USB_WRITE,
+				      addr, 0, buf, remainder,
+				      RTW_USB_CONTROL_MSG_TIMEOUT);
+		if (ret != remainder)
+			goto write_error;
+	}
+
+	return len;
+
+write_error:
+	dev_info(&udev->dev,
+		 "%s: Failed to write block at addr: %04x size: %04x\n",
+		 __func__, addr, blocksize);
+	return -EAGAIN;
+}
+
+static u32 rtl8xxxu_read_rfreg(struct rtl8xxxu_priv *priv,
+			       enum rtl8xxxu_rfpath path, u8 reg)
+{
+	u32 hssia, val32, retval;
+
+	hssia = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+	if (path != RF_A)
+		val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm2);
+	else
+		val32 = hssia;
+
+	val32 &= ~FPGA0_HSSI_PARM2_ADDR_MASK;
+	val32 |= (reg << FPGA0_HSSI_PARM2_ADDR_SHIFT);
+	val32 |= FPGA0_HSSI_PARM2_EDGE_READ;
+	hssia &= ~FPGA0_HSSI_PARM2_EDGE_READ;
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
+
+	udelay(10);
+
+	rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].hssiparm2, val32);
+	udelay(100);
+
+	hssia |= FPGA0_HSSI_PARM2_EDGE_READ;
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM2, hssia);
+	udelay(10);
+
+	val32 = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hssiparm1);
+	if (val32 & FPGA0_HSSI_PARM1_PI)
+		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].hspiread);
+	else
+		retval = rtl8xxxu_read32(priv, rtl8xxxu_rfregs[path].lssiread);
+
+	retval &= 0xfffff;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_READ)
+		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
+			 __func__, reg, retval);
+	return retval;
+}
+
+static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
+				enum rtl8xxxu_rfpath path, u8 reg, u32 data)
+{
+	int ret, retval;
+	u32 dataaddr;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_WRITE)
+		dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
+			 __func__, reg, data);
+
+	data &= FPGA0_LSSI_PARM_DATA_MASK;
+	dataaddr = (reg << FPGA0_LSSI_PARM_ADDR_SHIFT) | data;
+
+	/* Use XB for path B */
+	ret = rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].lssiparm, dataaddr);
+	if (ret != sizeof(dataaddr))
+		retval = -EIO;
+	else
+		retval = 0;
+
+	udelay(1);
+
+	return retval;
+}
+
+static int rtl8723a_h2c_cmd(struct rtl8xxxu_priv *priv, struct h2c_cmd *h2c)
+{
+	struct device *dev = &priv->udev->dev;
+	int mbox_nr, retry, retval = 0;
+	int mbox_reg, mbox_ext_reg;
+	u8 val8;
+
+	mutex_lock(&priv->h2c_mutex);
+
+	mbox_nr = priv->next_mbox;
+	mbox_reg = REG_HMBOX_0 + (mbox_nr * 4);
+	mbox_ext_reg = REG_HMBOX_EXT_0 + (mbox_nr * 2);
+
+	/*
+	 * MBOX ready?
+	 */
+	retry = 100;
+	do {
+		val8 = rtl8xxxu_read8(priv, REG_HMTFR);
+		if (!(val8 & BIT(mbox_nr)))
+			break;
+	} while (retry--);
+
+	if (!retry) {
+		dev_dbg(dev, "%s: Mailbox busy\n", __func__);
+		retval = -EBUSY;
+		goto error;
+	}
+
+	/*
+	 * Need to swap as it's being swapped again by rtl8xxxu_write16/32()
+	 */
+	if (h2c->cmd.cmd & H2C_EXT) {
+		rtl8xxxu_write16(priv, mbox_ext_reg,
+				 le16_to_cpu(h2c->raw.ext));
+		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
+			dev_info(dev, "H2C_EXT %04x\n",
+				 le16_to_cpu(h2c->raw.ext));
+	}
+	rtl8xxxu_write32(priv, mbox_reg, le32_to_cpu(h2c->raw.data));
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_H2C)
+		dev_info(dev, "H2C %08x\n", le32_to_cpu(h2c->raw.data));
+
+	priv->next_mbox = (mbox_nr + 1) % H2C_MAX_MBOX;
+
+error:
+	mutex_unlock(&priv->h2c_mutex);
+	return retval;
+}
+
+static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u32 val32;
+
+	val8 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
+	val8 |= BIT(0) | BIT(3);
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, val8);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
+	val32 &= ~(BIT(4) | BIT(5));
+	val32 |= BIT(3);
+	if (priv->rf_paths == 2) {
+		val32 &= ~(BIT(20) | BIT(21));
+		val32 |= BIT(19);
+	}
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	val32 &= ~OFDM_RF_PATH_TX_MASK;
+	if (priv->tx_paths == 2)
+		val32 |= OFDM_RF_PATH_TX_A | OFDM_RF_PATH_TX_B;
+	else if (priv->rtlchip == 0x8192c || priv->rtlchip == 0x8191c)
+		val32 |= OFDM_RF_PATH_TX_B;
+	else
+		val32 |= OFDM_RF_PATH_TX_A;
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 &= ~FPGA_RF_MODE_JAPAN;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x63db25a0);
+	else
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x631b25a0);
+
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x32d95);
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x32d95);
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
+}
+
+static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv)
+{
+	u8 sps0;
+	u32 val32;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	sps0 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
+
+	/* RF RX code for preamble power saving */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_PARM);
+	val32 &= ~(BIT(3) | BIT(4) | BIT(5));
+	if (priv->rf_paths == 2)
+		val32 &= ~(BIT(19) | BIT(20) | BIT(21));
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_PARM, val32);
+
+	/* Disable TX for four paths */
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	val32 &= ~OFDM_RF_PATH_TX_MASK;
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+	/* Enable power saving */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 |= FPGA_RF_MODE_JAPAN;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	/* AFE control register to power down bits [30:22] */
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x00db25a0);
+	else
+		rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, 0x001b25a0);
+
+	/* Power down RF module */
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0);
+	if (priv->rf_paths == 2)
+		rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0);
+
+	sps0 &= ~(BIT(0) | BIT(3));
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, sps0);
+}
+
+
+static void rtl8723a_stop_tx_beacon(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL + 2);
+	val8 &= ~BIT(6);
+	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL + 2, val8);
+
+	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 1, 0x64);
+	val8 = rtl8xxxu_read8(priv, REG_TBTT_PROHIBIT + 2);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_TBTT_PROHIBIT + 2, val8);
+}
+
+
+/*
+ * The rtl8723a has 3 channel groups for it's efuse settings. It only
+ * supports the 2.4GHz band, so channels 1 - 14:
+ *  group 0: channels 1 - 3
+ *  group 1: channels 4 - 9
+ *  group 2: channels 10 - 14
+ *
+ * Note: We index from 0 in the code
+ */
+static int rtl8723a_channel_to_group(int channel)
+{
+	int group;
+
+	if (channel < 4)
+		group = 0;
+	else if (channel < 10)
+		group = 1;
+	else
+		group = 2;
+
+	return group;
+}
+
+static void rtl8723au_config_channel(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u32 val32, rsr;
+	u8 val8, opmode;
+	bool ht = true;
+	int sec_ch_above, channel;
+	int i;
+
+	opmode = rtl8xxxu_read8(priv, REG_BW_OPMODE);
+	rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	channel = hw->conf.chandef.chan->hw_value;
+
+	switch (hw->conf.chandef.width) {
+	case NL80211_CHAN_WIDTH_20_NOHT:
+		ht = false;
+	case NL80211_CHAN_WIDTH_20:
+		opmode |= BW_OPMODE_20MHZ;
+		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+		val32 &= ~FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
+		val32 &= ~FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
+		val32 |= FPGA0_ANALOG2_20MHZ;
+		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
+		break;
+	case NL80211_CHAN_WIDTH_40:
+		if (hw->conf.chandef.center_freq1 >
+		    hw->conf.chandef.chan->center_freq) {
+			sec_ch_above = 1;
+			channel += 2;
+		} else {
+			sec_ch_above = 0;
+			channel -= 2;
+		}
+
+		opmode &= ~BW_OPMODE_20MHZ;
+		rtl8xxxu_write8(priv, REG_BW_OPMODE, opmode);
+		rsr &= ~RSR_RSC_BANDWIDTH_40M;
+		if (sec_ch_above)
+			rsr |= RSR_RSC_UPPER_SUB_CHANNEL;
+		else
+			rsr |= RSR_RSC_LOWER_SUB_CHANNEL;
+		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, rsr);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+		val32 |= FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_RF_MODE);
+		val32 |= FPGA_RF_MODE;
+		rtl8xxxu_write32(priv, REG_FPGA1_RF_MODE, val32);
+
+		/*
+		 * Set Control channel to upper or lower. These settings
+		 * are required only for 40MHz
+		 */
+		val32 = rtl8xxxu_read32(priv, REG_CCK0_SYSTEM);
+		val32 &= ~CCK0_SIDEBAND;
+		if (!sec_ch_above)
+			val32 |= CCK0_SIDEBAND;
+		rtl8xxxu_write32(priv, REG_CCK0_SYSTEM, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
+		val32 &= ~OFDM_LSTF_PRIME_CH_MASK; /* 0xc00 */
+		if (sec_ch_above)
+			val32 |= OFDM_LSTF_PRIME_CH_LOW;
+		else
+			val32 |= OFDM_LSTF_PRIME_CH_HIGH;
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_ANALOG2);
+		val32 &= ~FPGA0_ANALOG2_20MHZ;
+		rtl8xxxu_write32(priv, REG_FPGA0_ANALOG2, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
+		val32 &= ~(FPGA0_PS_LOWER_CHANNEL | FPGA0_PS_UPPER_CHANNEL);
+		if (sec_ch_above)
+			val32 |= FPGA0_PS_UPPER_CHANNEL;
+		else
+			val32 |= FPGA0_PS_LOWER_CHANNEL;
+		rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
+		break;
+
+	default:
+		break;
+	}
+
+	for (i = RF_A; i < priv->rf_paths; i++) {
+		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
+		val32 &= ~MODE_AG_CHANNEL_MASK;
+		val32 |= channel;
+		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
+	}
+
+	if (ht)
+		val8 = 0x0e;
+	else
+		val8 = 0x0a;
+
+	rtl8xxxu_write8(priv, REG_SIFS_CCK + 1, val8);
+	rtl8xxxu_write8(priv, REG_SIFS_OFDM + 1, val8);
+
+	rtl8xxxu_write16(priv, REG_R2T_SIFS, 0x0808);
+	rtl8xxxu_write16(priv, REG_T2T_SIFS, 0x0a0a);
+
+	for (i = RF_A; i < priv->rf_paths; i++) {
+		val32 = rtl8xxxu_read_rfreg(priv, i, RF6052_REG_MODE_AG);
+		if (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40)
+			val32 &= ~MODE_AG_CHANNEL_20MHZ;
+		else
+			val32 |= MODE_AG_CHANNEL_20MHZ;
+		rtl8xxxu_write_rfreg(priv, i, RF6052_REG_MODE_AG, val32);
+	}
+}
+
+static void
+rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
+{
+	u8 cck[RTL8723A_MAX_RF_PATHS], ofdm[RTL8723A_MAX_RF_PATHS];
+	u8 ofdmbase[RTL8723A_MAX_RF_PATHS], mcsbase[RTL8723A_MAX_RF_PATHS];
+	u32 val32, ofdm_a, ofdm_b, mcs_a, mcs_b;
+	u8 val8;
+	int group, i;
+
+	group = rtl8723a_channel_to_group(channel);
+
+	cck[0] = priv->cck_tx_power_index_A[group];
+	cck[1] = priv->cck_tx_power_index_B[group];
+
+	ofdm[0] = priv->ht40_1s_tx_power_index_A[group];
+	ofdm[1] = priv->ht40_1s_tx_power_index_B[group];
+
+	ofdmbase[0] = ofdm[0] +	priv->ofdm_tx_power_index_diff[group].a;
+	ofdmbase[1] = ofdm[1] +	priv->ofdm_tx_power_index_diff[group].b;
+
+	mcsbase[0] = ofdm[0];
+	mcsbase[1] = ofdm[1];
+	if (!ht40) {
+		mcsbase[0] += priv->ht20_tx_power_index_diff[group].a;
+		mcsbase[1] += priv->ht20_tx_power_index_diff[group].b;
+	}
+
+	if (priv->tx_paths > 1) {
+		if (ofdm[0] > priv->ht40_2s_tx_power_index_diff[group].a)
+			ofdm[0] -=  priv->ht40_2s_tx_power_index_diff[group].a;
+		if (ofdm[1] > priv->ht40_2s_tx_power_index_diff[group].b)
+			ofdm[1] -=  priv->ht40_2s_tx_power_index_diff[group].b;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
+		dev_info(&priv->udev->dev,
+			 "%s: Setting TX power CCK A: %02x, "
+			 "CCK B: %02x, OFDM A: %02x, OFDM B: %02x\n",
+			 __func__, cck[0], cck[1], ofdm[0], ofdm[1]);
+
+	for (i = 0; i < RTL8723A_MAX_RF_PATHS; i++) {
+		if (cck[i] > RF6052_MAX_TX_PWR)
+			cck[i] = RF6052_MAX_TX_PWR;
+		if (ofdm[i] > RF6052_MAX_TX_PWR)
+			ofdm[i] = RF6052_MAX_TX_PWR;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32);
+	val32 &= 0xffff00ff;
+	val32 |= (cck[0] << 8);
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+	val32 &= 0xff;
+	val32 |= ((cck[0] << 8) | (cck[0] << 16) | (cck[0] << 24));
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+	val32 &= 0xffffff00;
+	val32 |= cck[1];
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK1_55_MCS32);
+	val32 &= 0xff;
+	val32 |= ((cck[1] << 8) | (cck[1] << 16) | (cck[1] << 24));
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK1_55_MCS32, val32);
+
+	ofdm_a = ofdmbase[0] | ofdmbase[0] << 8 |
+		ofdmbase[0] << 16 | ofdmbase[0] << 24;
+	ofdm_b = ofdmbase[1] | ofdmbase[1] << 8 |
+		ofdmbase[1] << 16 | ofdmbase[1] << 24;
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm_b);
+
+	mcs_a = mcsbase[0] | mcsbase[0] << 8 |
+		mcsbase[0] << 16 | mcsbase[0] << 24;
+	mcs_b = mcsbase[1] | mcsbase[1] << 8 |
+		mcsbase[1] << 16 | mcsbase[1] << 24;
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs_a);
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs_b);
+
+	rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs_a);
+	for (i = 0; i < 3; i++) {
+		if (i != 2)
+			val8 = (mcsbase[0] > 8) ? (mcsbase[0] - 8) : 0;
+		else
+			val8 = (mcsbase[0] > 6) ? (mcsbase[0] - 6) : 0;
+		rtl8xxxu_write8(priv, REG_OFDM0_XC_TX_IQ_IMBALANCE + i, val8);
+	}
+	rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs_b);
+	for (i = 0; i < 3; i++) {
+		if (i != 2)
+			val8 = (mcsbase[1] > 8) ? (mcsbase[1] - 8) : 0;
+		else
+			val8 = (mcsbase[1] > 6) ? (mcsbase[1] - 6) : 0;
+		rtl8xxxu_write8(priv, REG_OFDM0_XD_TX_IQ_IMBALANCE + i, val8);
+	}
+}
+
+static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
+				  enum nl80211_iftype linktype)
+{
+	u16 val8;
+
+	val8 = rtl8xxxu_read16(priv, REG_MSR);
+	val8 &= ~MSR_LINKTYPE_MASK;
+
+	switch (linktype) {
+	case NL80211_IFTYPE_UNSPECIFIED:
+		val8 |= MSR_LINKTYPE_NONE;
+		break;
+	case NL80211_IFTYPE_ADHOC:
+		val8 |= MSR_LINKTYPE_ADHOC;
+		break;
+	case NL80211_IFTYPE_STATION:
+		val8 |= MSR_LINKTYPE_STATION;
+		break;
+	case NL80211_IFTYPE_AP:
+		val8 |= MSR_LINKTYPE_AP;
+		break;
+	default:
+		goto out;
+	}
+
+	rtl8xxxu_write8(priv, REG_MSR, val8);
+out:
+	return;
+}
+
+static void
+rtl8xxxu_set_retry(struct rtl8xxxu_priv *priv, u16 short_retry, u16 long_retry)
+{
+	u16 val16;
+
+	val16 = ((short_retry << RETRY_LIMIT_SHORT_SHIFT) &
+		 RETRY_LIMIT_SHORT_MASK) |
+		((long_retry << RETRY_LIMIT_LONG_SHIFT) &
+		 RETRY_LIMIT_LONG_MASK);
+
+	rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
+}
+
+static void
+rtl8xxxu_set_spec_sifs(struct rtl8xxxu_priv *priv, u16 cck, u16 ofdm)
+{
+	u16 val16;
+
+	val16 = ((cck << SPEC_SIFS_CCK_SHIFT) & SPEC_SIFS_CCK_MASK) |
+		((ofdm << SPEC_SIFS_OFDM_SHIFT) & SPEC_SIFS_OFDM_MASK);
+
+	rtl8xxxu_write16(priv, REG_SPEC_SIFS, val16);
+}
+
+static void rtl8xxxu_print_chipinfo(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	char *cut;
+
+	switch (priv->chip_cut) {
+	case 0:
+		cut = "A";
+		break;
+	case 1:
+		cut = "B";
+		break;
+	default:
+		cut = "unknown";
+	}
+
+	dev_info(dev,
+		 "RTL%s rev %s (%s) %iT%iR, TX queues %i, WiFi=%i, BT=%i, GPS=%i, HI PA=%i\n",
+		 priv->chip_name, cut, priv->vendor_umc ? "UMC" : "TSMC",
+		 priv->tx_paths, priv->rx_paths, priv->ep_tx_count,
+		 priv->has_wifi, priv->has_bluetooth, priv->has_gps,
+		 priv->hi_pa);
+
+	dev_info(dev, "RTL%s MAC: %pM\n", priv->chip_name, priv->mac_addr);
+}
+
+static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	u32 val32, bonding;
+	u16 val16;
+
+	val32 = rtl8xxxu_read32(priv, REG_SYS_CFG);
+	priv->chip_cut = (val32 & SYS_CFG_CHIP_VERSION_MASK) >>
+		SYS_CFG_CHIP_VERSION_SHIFT;
+	if (val32 & SYS_CFG_TRP_VAUX_EN) {
+		dev_info(dev, "Unsupported test chip\n");
+		return -ENOTSUPP;
+	}
+
+	if (val32 & SYS_CFG_BT_FUNC) {
+		sprintf(priv->chip_name, "8723AU");
+		priv->rf_paths = 1;
+		priv->rx_paths = 1;
+		priv->tx_paths = 1;
+		priv->rtlchip = 0x8723a;
+
+		val32 = rtl8xxxu_read32(priv, REG_MULTI_FUNC_CTRL);
+		if (val32 & MULTI_WIFI_FUNC_EN)
+			priv->has_wifi = 1;
+		if (val32 & MULTI_BT_FUNC_EN)
+			priv->has_bluetooth = 1;
+		if (val32 & MULTI_GPS_FUNC_EN)
+			priv->has_gps = 1;
+	} else if (val32 & SYS_CFG_TYPE_ID) {
+		bonding = rtl8xxxu_read32(priv, REG_HPON_FSM);
+		bonding &= HPON_FSM_BONDING_MASK;
+		if (bonding == HPON_FSM_BONDING_1T2R) {
+			sprintf(priv->chip_name, "8191CU");
+			priv->rf_paths = 2;
+			priv->rx_paths = 2;
+			priv->tx_paths = 1;
+			priv->rtlchip = 0x8191c;
+		} else {
+			sprintf(priv->chip_name, "8192CU");
+			priv->rf_paths = 2;
+			priv->rx_paths = 2;
+			priv->tx_paths = 2;
+			priv->rtlchip = 0x8192c;
+		}
+		priv->has_wifi = 1;
+	} else {
+		sprintf(priv->chip_name, "8188CU");
+		priv->rf_paths = 1;
+		priv->rx_paths = 1;
+		priv->tx_paths = 1;
+		priv->rtlchip = 0x8188c;
+		priv->has_wifi = 1;
+	}
+
+	if (val32 & SYS_CFG_VENDOR_ID)
+		priv->vendor_umc = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_GPIO_OUTSTS);
+	priv->rom_rev = (val32 & GPIO_RF_RL_ID) >> 28;
+
+	val16 = rtl8xxxu_read16(priv, REG_NORMAL_SIE_EP_TX);
+	if (val16 & NORMAL_SIE_EP_TX_HIGH_MASK) {
+		priv->ep_tx_high_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	if (val16 & NORMAL_SIE_EP_TX_NORMAL_MASK) {
+		priv->ep_tx_normal_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	if (val16 & NORMAL_SIE_EP_TX_LOW_MASK) {
+		priv->ep_tx_low_queue = 1;
+		priv->ep_tx_count++;
+	}
+
+	/*
+	 * Fallback for devices that do not provide REG_NORMAL_SIE_EP_TX
+	 */
+	if (!priv->ep_tx_count) {
+		switch (priv->nr_out_eps) {
+		case 3:
+			priv->ep_tx_low_queue = 1;
+			priv->ep_tx_count++;
+		case 2:
+			priv->ep_tx_normal_queue = 1;
+			priv->ep_tx_count++;
+		case 1:
+			priv->ep_tx_high_queue = 1;
+			priv->ep_tx_count++;
+			break;
+		default:
+			dev_info(dev, "Unsupported USB TX end-points\n");
+			return -ENOTSUPP;
+		}
+	}
+
+	return 0;
+}
+
+static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
+{
+	if (priv->efuse_wifi.efuse8723.rtl_id != cpu_to_le16(0x8129))
+		return -EINVAL;
+
+	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8723.mac_addr);
+
+	memcpy(priv->cck_tx_power_index_A,
+	       priv->efuse_wifi.efuse8723.cck_tx_power_index_A,
+	       sizeof(priv->cck_tx_power_index_A));
+	memcpy(priv->cck_tx_power_index_B,
+	       priv->efuse_wifi.efuse8723.cck_tx_power_index_B,
+	       sizeof(priv->cck_tx_power_index_B));
+
+	memcpy(priv->ht40_1s_tx_power_index_A,
+	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_A,
+	       sizeof(priv->ht40_1s_tx_power_index_A));
+	memcpy(priv->ht40_1s_tx_power_index_B,
+	       priv->efuse_wifi.efuse8723.ht40_1s_tx_power_index_B,
+	       sizeof(priv->ht40_1s_tx_power_index_B));
+
+	memcpy(priv->ht20_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8723.ht20_tx_power_index_diff,
+	       sizeof(priv->ht20_tx_power_index_diff));
+	memcpy(priv->ofdm_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8723.ofdm_tx_power_index_diff,
+	       sizeof(priv->ofdm_tx_power_index_diff));
+
+	memcpy(priv->ht40_max_power_offset,
+	       priv->efuse_wifi.efuse8723.ht40_max_power_offset,
+	       sizeof(priv->ht40_max_power_offset));
+	memcpy(priv->ht20_max_power_offset,
+	       priv->efuse_wifi.efuse8723.ht20_max_power_offset,
+	       sizeof(priv->ht20_max_power_offset));
+
+	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
+		 priv->efuse_wifi.efuse8723.vendor_name);
+	dev_info(&priv->udev->dev, "Product: %.41s\n",
+		 priv->efuse_wifi.efuse8723.device_name);
+	return 0;
+}
+
+static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
+{
+	int i;
+
+	if (priv->efuse_wifi.efuse8192.rtl_id != cpu_to_le16(0x8129))
+		return -EINVAL;
+
+	ether_addr_copy(priv->mac_addr, priv->efuse_wifi.efuse8192.mac_addr);
+
+	memcpy(priv->cck_tx_power_index_A,
+	       priv->efuse_wifi.efuse8192.cck_tx_power_index_A,
+	       sizeof(priv->cck_tx_power_index_A));
+	memcpy(priv->cck_tx_power_index_B,
+	       priv->efuse_wifi.efuse8192.cck_tx_power_index_B,
+	       sizeof(priv->cck_tx_power_index_B));
+
+	memcpy(priv->ht40_1s_tx_power_index_A,
+	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_A,
+	       sizeof(priv->ht40_1s_tx_power_index_A));
+	memcpy(priv->ht40_1s_tx_power_index_B,
+	       priv->efuse_wifi.efuse8192.ht40_1s_tx_power_index_B,
+	       sizeof(priv->ht40_1s_tx_power_index_B));
+	memcpy(priv->ht40_2s_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ht40_2s_tx_power_index_diff,
+	       sizeof(priv->ht40_2s_tx_power_index_diff));
+
+	memcpy(priv->ht20_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ht20_tx_power_index_diff,
+	       sizeof(priv->ht20_tx_power_index_diff));
+	memcpy(priv->ofdm_tx_power_index_diff,
+	       priv->efuse_wifi.efuse8192.ofdm_tx_power_index_diff,
+	       sizeof(priv->ofdm_tx_power_index_diff));
+
+	memcpy(priv->ht40_max_power_offset,
+	       priv->efuse_wifi.efuse8192.ht40_max_power_offset,
+	       sizeof(priv->ht40_max_power_offset));
+	memcpy(priv->ht20_max_power_offset,
+	       priv->efuse_wifi.efuse8192.ht20_max_power_offset,
+	       sizeof(priv->ht20_max_power_offset));
+
+	dev_info(&priv->udev->dev, "Vendor: %.7s\n",
+		 priv->efuse_wifi.efuse8192.vendor_name);
+	dev_info(&priv->udev->dev, "Product: %.20s\n",
+		 priv->efuse_wifi.efuse8192.device_name);
+
+	if (priv->efuse_wifi.efuse8192.rf_regulatory & 0x20) {
+		sprintf(priv->chip_name, "8188RU");
+		priv->hi_pa = 1;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
+		unsigned char *raw = priv->efuse_wifi.raw;
+
+		dev_info(&priv->udev->dev,
+			 "%s: dumping efuse (0x%02zx bytes):\n",
+			 __func__, sizeof(struct rtl8192cu_efuse));
+		for (i = 0; i < sizeof(struct rtl8192cu_efuse); i += 8) {
+			dev_info(&priv->udev->dev, "%02x: "
+				 "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+				 raw[i], raw[i + 1], raw[i + 2],
+				 raw[i + 3], raw[i + 4], raw[i + 5],
+				 raw[i + 6], raw[i + 7]);
+		}
+	}
+	return 0;
+}
+
+static int
+rtl8xxxu_read_efuse8(struct rtl8xxxu_priv *priv, u16 offset, u8 *data)
+{
+	int i;
+	u8 val8;
+	u32 val32;
+
+	/* Write Address */
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 1, offset & 0xff);
+	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 2);
+	val8 &= 0xfc;
+	val8 |= (offset >> 8) & 0x03;
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 2, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_EFUSE_CTRL + 3);
+	rtl8xxxu_write8(priv, REG_EFUSE_CTRL + 3, val8 & 0x7f);
+
+	/* Poll for data read */
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+	for (i = 0; i < RTL8XXXU_MAX_REG_POLL; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+		if (val32 & BIT(31))
+			break;
+	}
+
+	if (i == RTL8XXXU_MAX_REG_POLL)
+		return -EIO;
+
+	udelay(50);
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+
+	*data = val32 & 0xff;
+	return 0;
+}
+
+static int rtl8xxxu_read_efuse(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int i, ret = 0;
+	u8 val8, word_mask, header, extheader;
+	u16 val16, efuse_addr, offset;
+	u32 val32;
+
+	val16 = rtl8xxxu_read16(priv, REG_9346CR);
+	if (val16 & EEPROM_ENABLE)
+		priv->has_eeprom = 1;
+	if (val16 & EEPROM_BOOT)
+		priv->boot_eeprom = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_TEST);
+	val32 = (val32 & ~EFUSE_SELECT_MASK) | EFUSE_WIFI_SELECT;
+	rtl8xxxu_write32(priv, REG_EFUSE_TEST, val32);
+
+	dev_dbg(dev, "Booting from %s\n",
+		priv->boot_eeprom ? "EEPROM" : "EFUSE");
+
+	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_ENABLE);
+
+	/*  1.2V Power: From VDDON with Power Cut(0x0000[15]), default valid */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
+	if (!(val16 & SYS_ISO_PWC_EV12V)) {
+		val16 |= SYS_ISO_PWC_EV12V;
+		rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
+	}
+	/*  Reset: 0x0000[28], default valid */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	if (!(val16 & SYS_FUNC_ELDR)) {
+		val16 |= SYS_FUNC_ELDR;
+		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+	}
+
+	/*
+	 * Clock: Gated(0x0008[5]) 8M(0x0008[1]) clock from ANA, default valid
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_CLKR);
+	if (!(val16 & SYS_CLK_LOADER_ENABLE) || !(val16 & SYS_CLK_ANA8M)) {
+		val16 |= (SYS_CLK_LOADER_ENABLE | SYS_CLK_ANA8M);
+		rtl8xxxu_write16(priv, REG_SYS_CLKR, val16);
+	}
+
+	/* Default value is 0xff */
+	memset(priv->efuse_wifi.raw, 0xff, EFUSE_MAP_LEN_8723A);
+
+	efuse_addr = 0;
+	while (efuse_addr < EFUSE_REAL_CONTENT_LEN_8723A) {
+		ret = rtl8xxxu_read_efuse8(priv, efuse_addr++, &header);
+		if (ret || header == 0xff)
+			goto exit;
+
+		if ((header & 0x1f) == 0x0f) {	/* extended header */
+			offset = (header & 0xe0) >> 5;
+
+			ret = rtl8xxxu_read_efuse8(priv, efuse_addr++,
+						   &extheader);
+			if (ret)
+				goto exit;
+			/* All words disabled */
+			if ((extheader & 0x0f) == 0x0f)
+				continue;
+
+			offset |= ((extheader & 0xf0) >> 1);
+			word_mask = extheader & 0x0f;
+		} else {
+			offset = (header >> 4) & 0x0f;
+			word_mask = header & 0x0f;
+		}
+
+		if (offset < EFUSE_MAX_SECTION_8723A) {
+			u16 map_addr;
+			/* Get word enable value from PG header */
+
+			/* We have 8 bits to indicate validity */
+			map_addr = offset * 8;
+			if (map_addr >= EFUSE_MAP_LEN_8723A) {
+				dev_warn(dev, "%s: Illegal map_addr (%04x), "
+					 "efuse corrupt!\n",
+					 __func__, map_addr);
+				ret = -EINVAL;
+				goto exit;
+			}
+			for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+				/* Check word enable condition in the section */
+				if (!(word_mask & BIT(i))) {
+					ret = rtl8xxxu_read_efuse8(priv,
+								   efuse_addr++,
+								   &val8);
+					if (ret)
+						goto exit;
+					priv->efuse_wifi.raw[map_addr++] = val8;
+
+					ret = rtl8xxxu_read_efuse8(priv,
+								   efuse_addr++,
+								   &val8);
+					if (ret)
+						goto exit;
+					priv->efuse_wifi.raw[map_addr++] = val8;
+				} else
+					map_addr += 2;
+			}
+		} else {
+			dev_warn(dev,
+				 "%s: Illegal offset (%04x), efuse corrupt!\n",
+				 __func__, offset);
+			ret = -EINVAL;
+			goto exit;
+		}
+	}
+
+exit:
+	rtl8xxxu_write8(priv, REG_EFUSE_ACCESS, EFUSE_ACCESS_DISABLE);
+
+	return ret;
+}
+
+static int rtl8xxxu_start_firmware(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int ret = 0, i;
+	u32 val32;
+
+	/* Poll checksum report */
+	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+		if (val32 & MCU_FW_DL_CSUM_REPORT)
+			break;
+	}
+
+	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
+		dev_warn(dev, "Firmware checksum poll timed out\n");
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+	val32 |= MCU_FW_DL_READY;
+	val32 &= ~MCU_WINT_INIT_READY;
+	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32);
+
+	/* Wait for firmware to become ready */
+	for (i = 0; i < RTL8XXXU_FIRMWARE_POLL_MAX; i++) {
+		val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+		if (val32 & MCU_WINT_INIT_READY)
+			break;
+
+		udelay(100);
+	}
+
+	if (i == RTL8XXXU_FIRMWARE_POLL_MAX) {
+		dev_warn(dev, "Firmware failed to start\n");
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_download_firmware(struct rtl8xxxu_priv *priv)
+{
+	int pages, remainder, i, ret;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	u8 *fwptr;
+
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC + 1);
+	val8 |= 4;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC + 1, val8);
+
+	/* 8051 enable */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16 | SYS_FUNC_CPU_ENABLE);
+
+	/* MCU firmware download enable */
+	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_ENABLE);
+
+	/* 8051 reset */
+	val32 = rtl8xxxu_read32(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write32(priv, REG_MCU_FW_DL, val32 & ~BIT(19));
+
+	/* Reset firmware download checksum */
+	val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, val8 | MCU_FW_DL_CSUM_REPORT);
+
+	pages = priv->fw_size / RTL_FW_PAGE_SIZE;
+	remainder = priv->fw_size % RTL_FW_PAGE_SIZE;
+
+	fwptr = priv->fw_data->data;
+
+	for (i = 0; i < pages; i++) {
+		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
+		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+
+		ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS,
+				      fwptr, RTL_FW_PAGE_SIZE);
+		if (ret != RTL_FW_PAGE_SIZE) {
+			ret = -EAGAIN;
+			goto fw_abort;
+		}
+
+		fwptr += RTL_FW_PAGE_SIZE;
+	}
+
+	if (remainder) {
+		val8 = rtl8xxxu_read8(priv, REG_MCU_FW_DL + 2) & 0xF8;
+		rtl8xxxu_write8(priv, REG_MCU_FW_DL + 2, val8 | i);
+		ret = rtl8xxxu_writeN(priv, REG_FW_START_ADDRESS,
+				      fwptr, remainder);
+		if (ret != remainder) {
+			ret = -EAGAIN;
+			goto fw_abort;
+		}
+	}
+
+	ret = 0;
+fw_abort:
+	/* MCU firmware download disable */
+	val16 = rtl8xxxu_read16(priv, REG_MCU_FW_DL);
+	rtl8xxxu_write16(priv, REG_MCU_FW_DL,
+			 val16 & (~MCU_FW_DL_ENABLE & 0xff));
+
+	return ret;
+}
+
+static int rtl8xxxu_load_firmware(struct rtl8xxxu_priv *priv, char *fw_name)
+{
+	struct device *dev = &priv->udev->dev;
+	const struct firmware *fw;
+	int ret = 0;
+	u16 signature;
+
+	dev_info(dev, "%s: Loading firmware %s\n", DRIVER_NAME, fw_name);
+	if (request_firmware(&fw, fw_name, &priv->udev->dev)) {
+		dev_warn(dev, "request_firmware(%s) failed\n", fw_name);
+		ret = -EAGAIN;
+		goto exit;
+	}
+	if (!fw) {
+		dev_warn(dev, "Firmware data not available\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	priv->fw_data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+	priv->fw_size = fw->size - sizeof(struct rtl8xxxu_firmware_header);
+
+	signature = le16_to_cpu(priv->fw_data->signature);
+	switch (signature & 0xfff0) {
+	case 0x92c0:
+	case 0x88c0:
+	case 0x2300:
+		break;
+	default:
+		ret = -EINVAL;
+		dev_warn(dev, "%s: Invalid firmware signature: 0x%04x\n",
+			 __func__, signature);
+	}
+
+	dev_info(dev, "Firmware revision %i.%i (signature 0x%04x)\n",
+		 le16_to_cpu(priv->fw_data->major_version),
+		 priv->fw_data->minor_version, signature);
+
+exit:
+	release_firmware(fw);
+	return ret;
+}
+
+static int rtl8723au_load_firmware(struct rtl8xxxu_priv *priv)
+{
+	char *fw_name;
+	int ret;
+
+	switch (priv->chip_cut) {
+	case 0:
+		fw_name = "rtlwifi/rtl8723aufw_A.bin";
+		break;
+	case 1:
+		if (priv->enable_bluetooth)
+			fw_name = "rtlwifi/rtl8723aufw_B.bin";
+		else
+			fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = rtl8xxxu_load_firmware(priv, fw_name);
+	return ret;
+}
+
+static int rtl8192cu_load_firmware(struct rtl8xxxu_priv *priv)
+{
+	char *fw_name;
+	int ret;
+
+	if (!priv->vendor_umc)
+		fw_name = "rtlwifi/rtl8192cufw_TMSC.bin";
+	else if (priv->chip_cut || priv->rtlchip == 0x8192c)
+		fw_name = "rtlwifi/rtl8192cufw_B.bin";
+	else
+		fw_name = "rtlwifi/rtl8192cufw_A.bin";
+
+	ret = rtl8xxxu_load_firmware(priv, fw_name);
+
+	return ret;
+}
+
+static void rtl8xxxu_firmware_self_reset(struct rtl8xxxu_priv *priv)
+{
+	u16 val16;
+	int i = 100;
+
+	/* Inform 8051 to perform reset */
+	rtl8xxxu_write8(priv, REG_HMTFR + 3, 0x20);
+
+	for (i = 100; i > 0; i--) {
+		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+
+		if (!(val16 & SYS_FUNC_CPU_ENABLE)) {
+			dev_dbg(&priv->udev->dev,
+				"%s: Firmware self reset success!\n", __func__);
+			break;
+		}
+		udelay(50);
+	}
+
+	if (!i) {
+		/* Force firmware reset */
+		val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+		val16 &= ~SYS_FUNC_CPU_ENABLE;
+		rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+	}
+}
+
+static int
+rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array)
+{
+	int i, ret;
+	u16 reg;
+	u8 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xffff && val == 0xff)
+			break;
+
+		ret = rtl8xxxu_write8(priv, reg, val);
+		if (ret != 1) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize MAC\n");
+			return -EAGAIN;
+		}
+	}
+
+	rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a);
+
+	return 0;
+}
+
+static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_reg32val *array)
+{
+	int i, ret;
+	u16 reg;
+	u32 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xffff && val == 0xffffffff)
+			break;
+
+		ret = rtl8xxxu_write32(priv, reg, val);
+		if (ret != sizeof(val)) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize PHY\n");
+			return -EAGAIN;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+/*
+ * Most of this is black magic retrieved from the old rtl8723au driver
+ */
+static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
+{
+	u8 val8, ldoa15, ldov12d, lpldo, ldohci12;
+	u32 val32;
+
+	/*
+	 * Todo: The vendor driver maintains a table of PHY register
+	 *       addresses, which is initialized here. Do we need this?
+	 */
+
+	val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
+	udelay(2);
+	val8 |= AFE_PLL_320_ENABLE;
+	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
+	udelay(2);
+
+	rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff);
+	udelay(2);
+
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	/* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */
+	val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
+	val32 &= ~AFE_XTAL_RF_GATE;
+	if (priv->has_bluetooth)
+		val32 &= ~AFE_XTAL_BT_GATE;
+	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
+
+	/* 6. 0x1f[7:0] = 0x07 */
+	val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
+	rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
+
+	if (priv->hi_pa)
+		rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table);
+	else if (priv->tx_paths == 2)
+		rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table);
+	else
+		rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table);
+
+
+	if (priv->rtlchip == 0x8188c && priv->hi_pa &&
+	    priv->vendor_umc && priv->chip_cut == 1)
+		rtl8xxxu_write8(priv, REG_OFDM0_AGC_PARM1 + 2, 0x50);
+
+	if (priv->tx_paths == 1 && priv->rx_paths == 2) {
+		/*
+		 * For 1T2R boards, patch the registers.
+		 *
+		 * It looks like 8191/2 1T2R boards use path B for TX
+		 */
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO);
+		val32 &= ~(BIT(0) | BIT(1));
+		val32 |= BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO);
+		val32 &= ~0x300033;
+		val32 |= 0x200022;
+		rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
+		val32 &= 0xff000000;
+		val32 |= 0x45000000;
+		rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+		val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK);
+		val32 |= (OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B |
+			  OFDM_RF_PATH_TX_B);
+		rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGC_PARM1);
+		val32 &= ~(BIT(4) | BIT(5));
+		val32 |= BIT(4);
+		rtl8xxxu_write32(priv, REG_OFDM0_AGC_PARM1, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_RFON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_CCK_RFON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_CCK_BBON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_CCK_BBON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_RFON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_OFDM_RFON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_OFDM_BBON);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_OFDM_BBON, val32);
+
+		val32 = rtl8xxxu_read32(priv, REG_TX_TO_TX);
+		val32 &= ~(BIT(27) | BIT(26));
+		val32 |= BIT(27);
+		rtl8xxxu_write32(priv, REG_TX_TO_TX, val32);
+	}
+
+	if (priv->hi_pa)
+		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table);
+	else
+		rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table);
+
+	if (priv->rtlchip == 0x8723a &&
+	    priv->efuse_wifi.efuse8723.version >= 0x01) {
+		val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);
+
+		val8 = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
+		val32 &= 0xff000fff;
+		val32 |= ((val8 | (val8 << 6)) << 12);
+
+		rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);
+	}
+
+	ldoa15 = LDOA15_ENABLE | LDOA15_OBUF;
+	ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT);
+	ldohci12 = 0x57;
+	lpldo = 1;
+	val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15;
+
+	rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32);
+
+	return 0;
+}
+
+static int rtl8xxxu_init_rf_regs(struct rtl8xxxu_priv *priv,
+				 struct rtl8xxxu_rfregval *array,
+				 enum rtl8xxxu_rfpath path)
+{
+	int i, ret;
+	u8 reg;
+	u32 val;
+
+	for (i = 0; ; i++) {
+		reg = array[i].reg;
+		val = array[i].val;
+
+		if (reg == 0xff && val == 0xffffffff)
+			break;
+
+		switch (reg) {
+		case 0xfe:
+			msleep(50);
+			continue;
+		case 0xfd:
+			mdelay(5);
+			continue;
+		case 0xfc:
+			mdelay(1);
+			continue;
+		case 0xfb:
+			udelay(50);
+			continue;
+		case 0xfa:
+			udelay(5);
+			continue;
+		case 0xf9:
+			udelay(1);
+			continue;
+		}
+
+		reg &= 0x3f;
+
+		ret = rtl8xxxu_write_rfreg(priv, path, reg, val);
+		if (ret) {
+			dev_warn(&priv->udev->dev,
+				 "Failed to initialize RF\n");
+			return -EAGAIN;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv,
+				struct rtl8xxxu_rfregval *table,
+				enum rtl8xxxu_rfpath path)
+{
+	u32 val32;
+	u16 val16, rfsi_rfenv;
+	u16 reg_sw_ctrl, reg_int_oe, reg_hssi_parm2;
+
+	switch (path) {
+	case RF_A:
+		reg_sw_ctrl = REG_FPGA0_XA_RF_SW_CTRL;
+		reg_int_oe = REG_FPGA0_XA_RF_INT_OE;
+		reg_hssi_parm2 = REG_FPGA0_XA_HSSI_PARM2;
+		break;
+	case RF_B:
+		reg_sw_ctrl = REG_FPGA0_XB_RF_SW_CTRL;
+		reg_int_oe = REG_FPGA0_XB_RF_INT_OE;
+		reg_hssi_parm2 = REG_FPGA0_XB_HSSI_PARM2;
+		break;
+	default:
+		dev_err(&priv->udev->dev, "%s:Unsupported RF path %c\n",
+			__func__, path + 'A');
+		return -EINVAL;
+	}
+	/* For path B, use XB */
+	rfsi_rfenv = rtl8xxxu_read16(priv, reg_sw_ctrl);
+	rfsi_rfenv &= FPGA0_RF_RFENV;
+
+	/*
+	 * These two we might be able to optimize into one
+	 */
+	val32 = rtl8xxxu_read32(priv, reg_int_oe);
+	val32 |= BIT(20);	/* 0x10 << 16 */
+	rtl8xxxu_write32(priv, reg_int_oe, val32);
+	udelay(1);
+
+	val32 = rtl8xxxu_read32(priv, reg_int_oe);
+	val32 |= BIT(4);
+	rtl8xxxu_write32(priv, reg_int_oe, val32);
+	udelay(1);
+
+	/*
+	 * These two we might be able to optimize into one
+	 */
+	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
+	val32 &= ~FPGA0_HSSI_3WIRE_ADDR_LEN;
+	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
+	udelay(1);
+
+	val32 = rtl8xxxu_read32(priv, reg_hssi_parm2);
+	val32 &= ~FPGA0_HSSI_3WIRE_DATA_LEN;
+	rtl8xxxu_write32(priv, reg_hssi_parm2, val32);
+	udelay(1);
+
+	rtl8xxxu_init_rf_regs(priv, table, path);
+
+	/* For path B, use XB */
+	val16 = rtl8xxxu_read16(priv, reg_sw_ctrl);
+	val16 &= ~FPGA0_RF_RFENV;
+	val16 |= rfsi_rfenv;
+	rtl8xxxu_write16(priv, reg_sw_ctrl, val16);
+
+	return 0;
+}
+
+static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data)
+{
+	int ret = -EBUSY;
+	int count = 0;
+	u32 value;
+
+	value = LLT_OP_WRITE | address << 8 | data;
+
+	rtl8xxxu_write32(priv, REG_LLT_INIT, value);
+
+	do {
+		value = rtl8xxxu_read32(priv, REG_LLT_INIT);
+		if ((value & LLT_OP_MASK) == LLT_OP_INACTIVE) {
+			ret = 0;
+			break;
+		}
+	} while (count++ < 20);
+
+	return ret;
+}
+
+static int rtl8xxxu_init_llt_table(struct rtl8xxxu_priv *priv, u8 last_tx_page)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < last_tx_page; i++) {
+		ret = rtl8xxxu_llt_write(priv, i, i + 1);
+		if (ret)
+			goto exit;
+	}
+
+	ret = rtl8xxxu_llt_write(priv, last_tx_page, 0xff);
+	if (ret)
+		goto exit;
+
+	/* Mark remaining pages as a ring buffer */
+	for (i = last_tx_page + 1; i < 0xff; i++) {
+		ret = rtl8xxxu_llt_write(priv, i, (i + 1));
+		if (ret)
+			goto exit;
+	}
+
+	/*  Let last entry point to the start entry of ring buffer */
+	ret = rtl8xxxu_llt_write(priv, 0xff, last_tx_page + 1);
+	if (ret)
+		goto exit;
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_init_queue_priority(struct rtl8xxxu_priv *priv)
+{
+	u16 val16, hi, lo;
+	u16 hiq, mgq, bkq, beq, viq, voq;
+	int hip, mgp, bkp, bep, vip, vop;
+	int ret = 0;
+
+	switch (priv->ep_tx_count) {
+	case 1:
+		if (priv->ep_tx_high_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+		} else if (priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_normal_queue) {
+			hi = TRXDMA_QUEUE_NORMAL;
+		} else {
+			hi = 0;
+			ret = -EINVAL;
+		}
+
+		hiq = hi;
+		mgq = hi;
+		bkq = hi;
+		beq = hi;
+		viq = hi;
+		voq = hi;
+
+		hip = 0;
+		mgp = 0;
+		bkp = 0;
+		bep = 0;
+		vip = 0;
+		vop = 0;
+		break;
+	case 2:
+		if (priv->ep_tx_high_queue && priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+			lo = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_normal_queue && priv->ep_tx_low_queue) {
+			hi = TRXDMA_QUEUE_NORMAL;
+			lo = TRXDMA_QUEUE_LOW;
+		} else if (priv->ep_tx_high_queue && priv->ep_tx_normal_queue) {
+			hi = TRXDMA_QUEUE_HIGH;
+			lo = TRXDMA_QUEUE_NORMAL;
+		} else {
+			ret = -EINVAL;
+			hi = 0;
+			lo = 0;
+		}
+
+		hiq = hi;
+		mgq = hi;
+		bkq = lo;
+		beq = lo;
+		viq = hi;
+		voq = hi;
+
+		hip = 0;
+		mgp = 0;
+		bkp = 1;
+		bep = 1;
+		vip = 0;
+		vop = 0;
+		break;
+	case 3:
+		beq = TRXDMA_QUEUE_LOW;
+		bkq = TRXDMA_QUEUE_LOW;
+		viq = TRXDMA_QUEUE_NORMAL;
+		voq = TRXDMA_QUEUE_HIGH;
+		mgq = TRXDMA_QUEUE_HIGH;
+		hiq = TRXDMA_QUEUE_HIGH;
+
+		hip = hiq ^ 3;
+		mgp = mgq ^ 3;
+		bkp = bkq ^ 3;
+		bep = beq ^ 3;
+		vip = viq ^ 3;
+		vop = viq ^ 3;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	/*
+	 * None of the vendor drivers are configuring the beacon
+	 * queue here .... why?
+	 */
+	if (!ret) {
+		val16 = rtl8xxxu_read16(priv, REG_TRXDMA_CTRL);
+		val16 &= 0x7;
+		val16 |= (voq << TRXDMA_CTRL_VOQ_SHIFT) |
+			(viq << TRXDMA_CTRL_VIQ_SHIFT) |
+			(beq << TRXDMA_CTRL_BEQ_SHIFT) |
+			(bkq << TRXDMA_CTRL_BKQ_SHIFT) |
+			(mgq << TRXDMA_CTRL_MGQ_SHIFT) |
+			(hiq << TRXDMA_CTRL_HIQ_SHIFT);
+		rtl8xxxu_write16(priv, REG_TRXDMA_CTRL, val16);
+
+		priv->pipe_out[TXDESC_QUEUE_VO] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[vop]);
+		priv->pipe_out[TXDESC_QUEUE_VI] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[vip]);
+		priv->pipe_out[TXDESC_QUEUE_BE] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[bep]);
+		priv->pipe_out[TXDESC_QUEUE_BK] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[bkp]);
+		priv->pipe_out[TXDESC_QUEUE_BEACON] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
+		priv->pipe_out[TXDESC_QUEUE_MGNT] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[mgp]);
+		priv->pipe_out[TXDESC_QUEUE_HIGH] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[hip]);
+		priv->pipe_out[TXDESC_QUEUE_CMD] =
+			usb_sndbulkpipe(priv->udev, priv->out_ep[0]);
+	}
+
+	return ret;
+}
+
+static void rtl8xxxu_fill_iqk_matrix_a(struct rtl8xxxu_priv *priv,
+				       bool iqk_ok, int result[][8],
+				       int candidate, bool tx_only)
+{
+	u32 oldval, x, tx0_a, reg;
+	int y, tx0_c;
+	u32 val32;
+
+	if (!iqk_ok)
+		return;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	oldval = val32 >> 22;
+
+	x = result[candidate][0];
+	if ((x & 0x00000200) != 0)
+		x = x | 0xfffffc00;
+	tx0_a = (x * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= tx0_a;
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(31);
+	if ((x * oldval >> 7) & 0x1)
+		val32 |= BIT(31);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	y = result[candidate][1];
+	if ((y & 0x00000200) != 0)
+		y = y | 0xfffffc00;
+	tx0_c = (y * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XC_TX_AFE);
+	val32 &= ~0xf0000000;
+	val32 |= (((tx0_c & 0x3c0) >> 6) << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_XC_TX_AFE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE);
+	val32 &= ~0x003f0000;
+	val32 |= ((tx0_c & 0x3f) << 16);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(29);
+	if ((y * oldval >> 7) & 0x1)
+		val32 |= BIT(29);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	if (tx_only) {
+		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
+		return;
+	}
+
+	reg = result[candidate][2];
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= (reg & 0x3ff);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
+
+	reg = result[candidate][3] & 0x3F;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE);
+	val32 &= ~0xfc00;
+	val32 |= ((reg << 10) & 0xfc00);
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_RX_IQ_IMBALANCE, val32);
+
+	reg = (result[candidate][3] >> 6) & 0xF;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_RX_IQ_EXT_ANTA);
+	val32 &= ~0xf0000000;
+	val32 |= (reg << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_RX_IQ_EXT_ANTA, val32);
+}
+
+static void rtl8xxxu_fill_iqk_matrix_b(struct rtl8xxxu_priv *priv,
+				       bool iqk_ok, int result[][8],
+				       int candidate, bool tx_only)
+{
+	u32 oldval, x, tx1_a, reg;
+	int y, tx1_c;
+	u32 val32;
+
+	if (!iqk_ok)
+		return;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	oldval = val32 >> 22;
+
+	x = result[candidate][4];
+	if ((x & 0x00000200) != 0)
+		x = x | 0xfffffc00;
+	tx1_a = (x * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= tx1_a;
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(27);
+	if ((x * oldval >> 7) & 0x1)
+		val32 |= BIT(27);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	y = result[candidate][5];
+	if ((y & 0x00000200) != 0)
+		y = y | 0xfffffc00;
+	tx1_c = (y * oldval) >> 8;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XD_TX_AFE);
+	val32 &= ~0xf0000000;
+	val32 |= (((tx1_c & 0x3c0) >> 6) << 28);
+	rtl8xxxu_write32(priv, REG_OFDM0_XD_TX_AFE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE);
+	val32 &= ~0x003f0000;
+	val32 |= ((tx1_c & 0x3f) << 16);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_TX_IQ_IMBALANCE, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_ENERGY_CCA_THRES);
+	val32 &= ~BIT(25);
+	if ((y * oldval >> 7) & 0x1)
+		val32 |= BIT(25);
+	rtl8xxxu_write32(priv, REG_OFDM0_ENERGY_CCA_THRES, val32);
+
+	if (tx_only) {
+		dev_dbg(&priv->udev->dev, "%s: only TX\n", __func__);
+		return;
+	}
+
+	reg = result[candidate][6];
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
+	val32 &= ~0x3ff;
+	val32 |= (reg & 0x3ff);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
+
+	reg = result[candidate][7] & 0x3f;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE);
+	val32 &= ~0xfc00;
+	val32 |= ((reg << 10) & 0xfc00);
+	rtl8xxxu_write32(priv, REG_OFDM0_XB_RX_IQ_IMBALANCE, val32);
+
+	reg = (result[candidate][7] >> 6) & 0xf;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_AGCR_SSI_TABLE);
+	val32 &= ~0x0000f000;
+	val32 |= (reg << 12);
+	rtl8xxxu_write32(priv, REG_OFDM0_AGCR_SSI_TABLE, val32);
+}
+
+#define MAX_TOLERANCE		5
+
+static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv,
+					int result[][8], int c1, int c2)
+{
+	u32 i, j, diff, simubitmap, bound = 0;
+	int candidate[2] = {-1, -1};	/* for path A and path B */
+	bool retval = true;
+
+	if (priv->tx_paths > 1)
+		bound = 8;
+	else
+		bound = 4;
+
+	simubitmap = 0;
+
+	for (i = 0; i < bound; i++) {
+		diff = (result[c1][i] > result[c2][i]) ?
+			(result[c1][i] - result[c2][i]) :
+			(result[c2][i] - result[c1][i]);
+		if (diff > MAX_TOLERANCE) {
+			if ((i == 2 || i == 6) && !simubitmap) {
+				if (result[c1][i] + result[c1][i + 1] == 0)
+					candidate[(i / 4)] = c2;
+				else if (result[c2][i] + result[c2][i + 1] == 0)
+					candidate[(i / 4)] = c1;
+				else
+					simubitmap = simubitmap | (1 << i);
+			} else {
+				simubitmap = simubitmap | (1 << i);
+			}
+		}
+	}
+
+	if (simubitmap == 0) {
+		for (i = 0; i < (bound / 4); i++) {
+			if (candidate[i] >= 0) {
+				for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+					result[3][j] = result[candidate[i]][j];
+				retval = false;
+			}
+		}
+		return retval;
+	} else if (!(simubitmap & 0x0f)) {
+		/* path A OK */
+		for (i = 0; i < 4; i++)
+			result[3][i] = result[c1][i];
+	} else if (!(simubitmap & 0xf0) && priv->tx_paths > 1) {
+		/* path B OK */
+		for (i = 4; i < 8; i++)
+			result[3][i] = result[c1][i];
+	}
+
+	return false;
+}
+
+static void
+rtl8xxxu_save_mac_regs(struct rtl8xxxu_priv *priv, const u32 *reg, u32 *backup)
+{
+	int i;
+
+	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		backup[i] = rtl8xxxu_read8(priv, reg[i]);
+
+	backup[i] = rtl8xxxu_read32(priv, reg[i]);
+}
+
+static void rtl8xxxu_restore_mac_regs(struct rtl8xxxu_priv *priv,
+				      const u32 *reg, u32 *backup)
+{
+	int i;
+
+	for (i = 0; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		rtl8xxxu_write8(priv, reg[i], backup[i]);
+
+	rtl8xxxu_write32(priv, reg[i], backup[i]);
+}
+
+static void rtl8xxxu_save_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
+			       u32 *backup, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		backup[i] = rtl8xxxu_read32(priv, regs[i]);
+}
+
+static void rtl8xxxu_restore_regs(struct rtl8xxxu_priv *priv, const u32 *regs,
+				  u32 *backup, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		rtl8xxxu_write32(priv, regs[i], backup[i]);
+}
+
+
+static void rtl8xxxu_path_adda_on(struct rtl8xxxu_priv *priv, const u32 *regs,
+				  bool path_a_on)
+{
+	u32 path_on;
+	int i;
+
+	path_on = path_a_on ? 0x04db25a4 : 0x0b1b25a4;
+	if (priv->tx_paths == 1) {
+		path_on = 0x0bdb25a0;
+		rtl8xxxu_write32(priv, regs[0], 0x0b1b25a0);
+	} else {
+		rtl8xxxu_write32(priv, regs[0], path_on);
+	}
+
+	for (i = 1 ; i < RTL8XXXU_ADDA_REGS ; i++)
+		rtl8xxxu_write32(priv, regs[i], path_on);
+}
+
+static void rtl8xxxu_mac_calibration(struct rtl8xxxu_priv *priv,
+				     const u32 *regs, u32 *backup)
+{
+	int i = 0;
+
+	rtl8xxxu_write8(priv, regs[i], 0x3f);
+
+	for (i = 1 ; i < (RTL8XXXU_MAC_REGS - 1); i++)
+		rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(3)));
+
+	rtl8xxxu_write8(priv, regs[i], (u8)(backup[i] & ~BIT(5)));
+}
+
+static int rtl8xxxu_iqk_path_a(struct rtl8xxxu_priv *priv)
+{
+	u32 reg_eac, reg_e94, reg_e9c, reg_ea4, val32;
+	int result = 0;
+
+	/* path-A IQK setting */
+	rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x10008c1f);
+	rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x10008c1f);
+	rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82140102);
+
+	val32 = (priv->rf_paths > 1) ? 0x28160202 :
+		/*IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202: */
+		0x28160502;
+	rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, val32);
+
+	/* path-B IQK setting */
+	if (priv->rf_paths > 1) {
+		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x10008c22);
+		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x10008c22);
+		rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82140102);
+		rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x28160202);
+	}
+
+	/* LO calibration setting */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x001028d1);
+
+	/* One shot, path A LOK & IQK */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
+	rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+	mdelay(1);
+
+	/* Check failed */
+	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+	reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
+	reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
+	reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2);
+
+	if (!(reg_eac & BIT(28)) &&
+	    ((reg_e94 & 0x03ff0000) != 0x01420000) &&
+	    ((reg_e9c & 0x03ff0000) != 0x00420000))
+		result |= 0x01;
+	else	/* If TX not OK, ignore RX */
+		goto out;
+
+	/* If TX is OK, check whether RX is OK */
+	if (!(reg_eac & BIT(27)) &&
+	    ((reg_ea4 & 0x03ff0000) != 0x01320000) &&
+	    ((reg_eac & 0x03ff0000) != 0x00360000))
+		result |= 0x02;
+	else
+		dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n",
+			 __func__);
+out:
+	return result;
+}
+
+static int rtl8xxxu_iqk_path_b(struct rtl8xxxu_priv *priv)
+{
+	u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	int result = 0;
+
+	/* One shot, path B LOK & IQK */
+	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002);
+	rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000);
+
+	mdelay(1);
+
+	/* Check failed */
+	reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+	reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+	reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+	reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+	reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+
+	if (!(reg_eac & BIT(31)) &&
+	    ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
+	    ((reg_ebc & 0x03ff0000) != 0x00420000))
+		result |= 0x01;
+	else
+		goto out;
+
+	if (!(reg_eac & BIT(30)) &&
+	    (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) &&
+	    (((reg_ecc & 0x03ff0000) >> 16) != 0x36))
+		result |= 0x02;
+	else
+		dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n",
+			 __func__);
+out:
+	return result;
+}
+
+static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
+				     int result[][8], int t)
+{
+	struct device *dev = &priv->udev->dev;
+	u32 i, val32;
+	int path_a_ok, path_b_ok;
+	int retry = 2;
+	const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
+		REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
+		REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
+		REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
+		REG_TX_OFDM_BBON, REG_TX_TO_RX,
+		REG_TX_TO_TX, REG_RX_CCK,
+		REG_RX_OFDM, REG_RX_WAIT_RIFS,
+		REG_RX_TO_RX, REG_STANDBY,
+		REG_SLEEP, REG_PMPD_ANAEN
+	};
+	const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
+		REG_TXPAUSE, REG_BEACON_CTRL,
+		REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
+	};
+	const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
+		REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
+		REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
+		REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
+		REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE
+	};
+
+	/*
+	 * Note: IQ calibration must be performed after loading
+	 *       PHY_REG.txt , and radio_a, radio_b.txt
+	 */
+
+	if (t == 0) {
+		/* Save ADDA parameters, turn Path A ADDA on */
+		rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
+				   RTL8XXXU_ADDA_REGS);
+		rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+		rtl8xxxu_save_regs(priv, iqk_bb_regs,
+				   priv->bb_backup, RTL8XXXU_BB_REGS);
+	}
+
+	rtl8xxxu_path_adda_on(priv, adda_regs, true);
+
+	if (t == 0) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
+		if (val32 & FPGA0_HSSI_PARM1_PI)
+			priv->pi_enabled = 1;
+	}
+
+	if (!priv->pi_enabled) {
+		/* Switch BB to PI mode to do IQ Calibration. */
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
+		rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 &= ~FPGA_RF_MODE_CCK;
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
+	rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
+	rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
+	val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+	val32 &= ~BIT(10);
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
+	val32 &= ~BIT(10);
+	rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
+
+	if (priv->tx_paths > 1) {
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+		rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000);
+	}
+
+	/* MAC settings */
+	rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
+
+	/* Page B init */
+	rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000);
+
+	if (priv->tx_paths > 1)
+		rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000);
+
+	/* IQ calibration setting */
+	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+	rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+	rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
+	for (i = 0; i < retry; i++) {
+		path_a_ok = rtl8xxxu_iqk_path_a(priv);
+		if (path_a_ok == 0x03) {
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_BEFORE_IQK_A);
+			result[t][0] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_AFTER_IQK_A);
+			result[t][1] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_RX_POWER_BEFORE_IQK_A_2);
+			result[t][2] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_RX_POWER_AFTER_IQK_A_2);
+			result[t][3] = (val32 >> 16) & 0x3ff;
+			break;
+		} else if (i == (retry - 1) && path_a_ok == 0x01) {
+			/* TX IQK OK */
+			dev_dbg(dev, "%s: Path A IQK Only Tx Success!!\n",
+				__func__);
+
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_BEFORE_IQK_A);
+			result[t][0] = (val32 >> 16) & 0x3ff;
+			val32 = rtl8xxxu_read32(priv,
+						REG_TX_POWER_AFTER_IQK_A);
+			result[t][1] = (val32 >> 16) & 0x3ff;
+		}
+	}
+
+	if (!path_a_ok)
+		dev_dbg(dev, "%s: Path A IQK failed!\n", __func__);
+
+	if (priv->tx_paths > 1) {
+		/*
+		 * Path A into standby
+		 */
+		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x0);
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+		rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+		/* Turn Path B ADDA on */
+		rtl8xxxu_path_adda_on(priv, adda_regs, false);
+
+		for (i = 0; i < retry; i++) {
+			path_b_ok = rtl8xxxu_iqk_path_b(priv);
+			if (path_b_ok == 0x03) {
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+				result[t][4] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+				result[t][5] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+				result[t][6] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+				result[t][7] = (val32 >> 16) & 0x3ff;
+				break;
+			} else if (i == (retry - 1) && path_b_ok == 0x01) {
+				/* TX IQK OK */
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+				result[t][4] = (val32 >> 16) & 0x3ff;
+				val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+				result[t][5] = (val32 >> 16) & 0x3ff;
+			}
+		}
+
+		if (!path_b_ok)
+			dev_dbg(dev, "%s: Path B IQK failed!\n", __func__);
+	}
+
+	/* Back to BB mode, load original value */
+	rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0);
+
+	if (t) {
+		if (!priv->pi_enabled) {
+			/*
+			 * Switch back BB to SI mode after finishing
+			 * IQ Calibration
+			 */
+			val32 = 0x01000000;
+			rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, val32);
+			rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, val32);
+		}
+
+		/* Reload ADDA power saving parameters */
+		rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup,
+				      RTL8XXXU_ADDA_REGS);
+
+		/* Reload MAC parameters */
+		rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+
+		/* Reload BB parameters */
+		rtl8xxxu_restore_regs(priv, iqk_bb_regs,
+				      priv->bb_backup, RTL8XXXU_BB_REGS);
+
+		/* Restore RX initial gain */
+		rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00032ed3);
+
+		if (priv->tx_paths > 1) {
+			rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM,
+					 0x00032ed3);
+		}
+
+		/* Load 0xe30 IQC default value */
+		rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00);
+		rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00);
+	}
+}
+
+static void rtl8723a_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
+{
+	struct device *dev = &priv->udev->dev;
+	int result[4][8];	/* last is final result */
+	int i, candidate;
+	bool path_a_ok, path_b_ok;
+	u32 reg_e94, reg_e9c, reg_ea4, reg_eac;
+	u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+	s32 reg_tmp = 0;
+	bool simu;
+
+	memset(result, 0, sizeof(result));
+	candidate = -1;
+
+	path_a_ok = false;
+	path_b_ok = false;
+
+	rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+
+	for (i = 0; i < 3; i++) {
+		rtl8xxxu_phy_iqcalibrate(priv, result, i);
+
+		if (i == 1) {
+			simu = rtl8xxxu_simularity_compare(priv, result, 0, 1);
+			if (simu) {
+				candidate = 0;
+				break;
+			}
+		}
+
+		if (i == 2) {
+			simu = rtl8xxxu_simularity_compare(priv, result, 0, 2);
+			if (simu) {
+				candidate = 0;
+				break;
+			}
+
+			simu = rtl8xxxu_simularity_compare(priv, result, 1, 2);
+			if (simu) {
+				candidate = 1;
+			} else {
+				for (i = 0; i < 8; i++)
+					reg_tmp += result[3][i];
+
+				if (reg_tmp)
+					candidate = 3;
+				else
+					candidate = -1;
+			}
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		reg_e94 = result[i][0];
+		reg_e9c = result[i][1];
+		reg_ea4 = result[i][2];
+		reg_eac = result[i][3];
+		reg_eb4 = result[i][4];
+		reg_ebc = result[i][5];
+		reg_ec4 = result[i][6];
+		reg_ecc = result[i][7];
+	}
+
+	if (candidate >= 0) {
+		reg_e94 = result[candidate][0];
+		priv->rege94 =  reg_e94;
+		reg_e9c = result[candidate][1];
+		priv->rege9c = reg_e9c;
+		reg_ea4 = result[candidate][2];
+		reg_eac = result[candidate][3];
+		reg_eb4 = result[candidate][4];
+		priv->regeb4 = reg_eb4;
+		reg_ebc = result[candidate][5];
+		priv->regebc = reg_ebc;
+		reg_ec4 = result[candidate][6];
+		reg_ecc = result[candidate][7];
+		dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate);
+		dev_dbg(dev,
+			"%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x "
+			"ecc=%x\n ", __func__, reg_e94, reg_e9c,
+			reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc);
+		path_a_ok = true;
+		path_b_ok = true;
+	} else {
+		reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100;
+		reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0;
+	}
+
+	if (reg_e94 && candidate >= 0)
+		rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result,
+					   candidate, (reg_ea4 == 0));
+
+	if (priv->tx_paths > 1 && reg_eb4)
+		rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
+					   candidate, (reg_ec4 == 0));
+
+	rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+			   priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
+}
+
+static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
+{
+	u32 val32;
+	u32 rf_amode, rf_bmode = 0, lstf;
+
+	/* Check continuous TX and Packet TX */
+	lstf = rtl8xxxu_read32(priv, REG_OFDM1_LSTF);
+
+	if (lstf & OFDM_LSTF_MASK) {
+		/* Disable all continuous TX */
+		val32 = lstf & ~OFDM_LSTF_MASK;
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, val32);
+
+		/* Read original RF mode Path A */
+		rf_amode = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_AC);
+
+		/* Set RF mode to standby Path A */
+		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC,
+				     (rf_amode & 0x8ffff) | 0x10000);
+
+		/* Path-B */
+		if (priv->tx_paths > 1) {
+			rf_bmode = rtl8xxxu_read_rfreg(priv, RF_B,
+						       RF6052_REG_AC);
+
+			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
+					     (rf_bmode & 0x8ffff) | 0x10000);
+		}
+	} else {
+		/*  Deal with Packet TX case */
+		/*  block all queues */
+		rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+	}
+
+	/* Start LC calibration */
+	val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_MODE_AG);
+	val32 |= 0x08000;
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, val32);
+
+	msleep(100);
+
+	/* Restore original parameters */
+	if (lstf & OFDM_LSTF_MASK) {
+		/* Path-A */
+		rtl8xxxu_write32(priv, REG_OFDM1_LSTF, lstf);
+		rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, rf_amode);
+
+		/* Path-B */
+		if (priv->tx_paths > 1)
+			rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC,
+					     rf_bmode);
+	} else /*  Deal with Packet TX case */
+		rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
+}
+
+static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv)
+{
+	int i;
+	u16 reg;
+
+	reg = REG_MACID;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]);
+
+	return 0;
+}
+
+static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid)
+{
+	int i;
+	u16 reg;
+
+	dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid);
+
+	reg = REG_BSSID;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl8xxxu_write8(priv, reg + i, bssid[i]);
+
+	return 0;
+}
+
+static void
+rtl8xxxu_set_ampdu_factor(struct rtl8xxxu_priv *priv, u8 ampdu_factor)
+{
+	u8 vals[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+	u8 max_agg = 0xf;
+	int i;
+
+	ampdu_factor = 1 << (ampdu_factor + 2);
+	if (ampdu_factor > max_agg)
+		ampdu_factor = max_agg;
+
+	for (i = 0; i < 4; i++) {
+		if ((vals[i] & 0xf0) > (ampdu_factor << 4))
+			vals[i] = (vals[i] & 0x0f) | (ampdu_factor << 4);
+
+		if ((vals[i] & 0x0f) > ampdu_factor)
+			vals[i] = (vals[i] & 0xf0) | ampdu_factor;
+
+		rtl8xxxu_write8(priv, REG_AGGLEN_LMT + i, vals[i]);
+	}
+}
+
+static void rtl8xxxu_set_ampdu_min_space(struct rtl8xxxu_priv *priv, u8 density)
+{
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_AMPDU_MIN_SPACE);
+	val8 &= 0xf8;
+	val8 |= density;
+	rtl8xxxu_write8(priv, REG_AMPDU_MIN_SPACE, val8);
+}
+
+static int rtl8xxxu_active_to_emu(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	int count, ret;
+
+	/* Start of rtl8723AU_card_enable_flow */
+	/* Act to Cardemu sequence*/
+	/* Turn off RF */
+	rtl8xxxu_write8(priv, REG_RF_CTRL, 0);
+
+	/* 0x004E[7] = 0, switch DPDT_SEL_P output from register 0x0065[2] */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 &= ~LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+	/* 0x0005[1] = 1 turn off MAC by HW state machine*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 |= BIT(1);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+		if ((val8 & BIT(1)) == 0)
+			break;
+		udelay(10);
+	}
+
+	if (!count) {
+		dev_warn(&priv->udev->dev, "%s: Disabling MAC timed out\n",
+			 __func__);
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* 0x0000[5] = 1 analog Ips to digital, 1:isolation */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+	val8 |= SYS_ISO_ANALOG_IPS;
+	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+
+	/* 0x0020[0] = 0 disable LDOA12 MACRO block*/
+	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
+	val8 &= ~LDOA15_ENABLE;
+	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u8 val32;
+	int count, ret;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	/*
+	 * Poll - wait for RX packet to complete
+	 */
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, 0x5f8);
+		if (!val32)
+			break;
+		udelay(10);
+	}
+
+	if (!count) {
+		dev_warn(&priv->udev->dev,
+			 "%s: RX poll timed out (0x05f8)\n", __func__);
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* Disable CCK and OFDM, clock gated */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 &= ~SYS_FUNC_BBRSTB;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	udelay(2);
+
+	/* Reset baseband */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_FUNC);
+	val8 &= ~SYS_FUNC_BB_GLB_RSTN;
+	rtl8xxxu_write8(priv, REG_SYS_FUNC, val8);
+
+	/* Reset MAC TRX */
+	val8 = rtl8xxxu_read8(priv, REG_CR);
+	val8 = CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE;
+	rtl8xxxu_write8(priv, REG_CR, val8);
+
+	/* Reset MAC TRX */
+	val8 = rtl8xxxu_read8(priv, REG_CR + 1);
+	val8 &= ~BIT(1); /* CR_SECURITY_ENABLE */
+	rtl8xxxu_write8(priv, REG_CR + 1, val8);
+
+	/* Respond TX OK to scheduler */
+	val8 = rtl8xxxu_read8(priv, REG_DUAL_TSF_RST);
+	val8 |= DUAL_TSF_TX_OK;
+	rtl8xxxu_write8(priv, REG_DUAL_TSF_RST, val8);
+
+exit:
+	return ret;
+}
+
+static void rtl8xxxu_disabled_to_emu(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	/* Clear suspend enable and power down enable*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(7));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* 0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/
+	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
+
+	/* 0x04[12:11] = 11 enable WL suspend*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(4));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+}
+
+static int rtl8xxxu_emu_to_active(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u32 val32;
+	int count, ret = 0;
+
+	/* 0x20[0] = 1 enable LDOA12 MACRO block for all interface*/
+	val8 = rtl8xxxu_read8(priv, REG_LDOA15_CTRL);
+	val8 |= LDOA15_ENABLE;
+	rtl8xxxu_write8(priv, REG_LDOA15_CTRL, val8);
+
+	/* 0x67[0] = 0 to disable BT_GPS_SEL pins*/
+	val8 = rtl8xxxu_read8(priv, 0x0067);
+	val8 &= ~BIT(4);
+	rtl8xxxu_write8(priv, 0x0067, val8);
+
+	mdelay(1);
+
+	/* 0x00[5] = 0 release analog Ips to digital, 1:isolation */
+	val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+	val8 &= ~SYS_ISO_ANALOG_IPS;
+	rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+
+	/* disable SW LPS 0x04[10]= 0 */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(2);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* wait till 0x04[17] = 1 power ready*/
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+		if (val32 & BIT(17))
+			break;
+
+		udelay(10);
+	}
+
+	if (!count) {
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* We should be able to optimize the following three entries into one */
+
+	/* release WLON reset 0x04[16]= 1*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
+
+	/* disable HWPDN 0x04[15]= 0*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(7);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* disable WL suspend*/
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~(BIT(3) | BIT(4));
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* set, then poll until 0 */
+	val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+	val32 |= APS_FSMCO_MAC_ENABLE;
+	rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
+
+	for (count = RTL8XXXU_MAX_REG_POLL; count; count--) {
+		val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
+		if ((val32 & APS_FSMCO_MAC_ENABLE) == 0) {
+			ret = 0;
+			break;
+		}
+		udelay(10);
+	}
+
+	if (!count) {
+		ret = -EBUSY;
+		goto exit;
+	}
+
+	/* 0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */
+	/*
+	 * Note: Vendor driver actually clears this bit, despite the
+	 * documentation claims it's being set!
+	 */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 |= LEDCFG2_DPDT_SELECT;
+	val8 &= ~LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_emu_to_disabled(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+
+	/* 0x0007[7:0] = 0x20 SOP option to disable BG/MB */
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 3, 0x20);
+
+	/* 0x04[12:11] = 01 enable WL suspend */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 &= ~BIT(4);
+	val8 |= BIT(3);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+	val8 |= BIT(7);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+	/* 0x48[16] = 1 to enable GPIO9 as EXT wakeup */
+	val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
+
+	return 0;
+}
+
+static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int ret;
+
+	/*
+	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
+	 */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
+
+	rtl8xxxu_disabled_to_emu(priv);
+
+	ret = rtl8xxxu_emu_to_active(priv);
+	if (ret)
+		goto exit;
+
+	/*
+	 * 0x0004[19] = 1, reset 8051
+	 */
+	val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 2);
+	val8 |= BIT(3);
+	rtl8xxxu_write8(priv, REG_APS_FSMCO + 2, val8);
+
+	/*
+	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
+	 * Set CR bit10 to enable 32k calibration.
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= (CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
+		  CR_TXDMA_ENABLE | CR_RXDMA_ENABLE |
+		  CR_PROTOCOL_ENABLE | CR_SCHEDULE_ENABLE |
+		  CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE |
+		  CR_SECURITY_ENABLE | CR_CALTIMER_ENABLE);
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	/* For EFuse PG */
+	val32 = rtl8xxxu_read32(priv, REG_EFUSE_CTRL);
+	val32 &= ~(BIT(28) | BIT(29) | BIT(30));
+	val32 |= (0x06 << 28);
+	rtl8xxxu_write32(priv, REG_EFUSE_CTRL, val32);
+exit:
+	return ret;
+}
+
+static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int i;
+
+	for (i = 100; i; i--) {
+		val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO);
+		if (val8 & APS_FSMCO_PFM_ALDN)
+			break;
+	}
+
+	if (!i) {
+		pr_info("%s: Poll failed\n", __func__);
+		return -ENODEV;
+	}
+
+	/*
+	 * RSV_CTRL 0x001C[7:0] = 0x00, unlock ISO/CLK/Power control register
+	 */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0);
+	rtl8xxxu_write8(priv, REG_SPS0_CTRL, 0x2b);
+	udelay(100);
+
+	val8 = rtl8xxxu_read8(priv, REG_LDOV12D_CTRL);
+	if (!(val8 & LDOV12D_ENABLE)) {
+		pr_info("%s: Enabling LDOV12D (%02x)\n", __func__, val8);
+		val8 |= LDOV12D_ENABLE;
+		rtl8xxxu_write8(priv, REG_LDOV12D_CTRL, val8);
+
+		udelay(100);
+
+		val8 = rtl8xxxu_read8(priv, REG_SYS_ISO_CTRL);
+		val8 &= ~SYS_ISO_MD2PP;
+		rtl8xxxu_write8(priv, REG_SYS_ISO_CTRL, val8);
+	}
+
+	/*
+	 * Auto enable WLAN
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
+	val16 |= APS_FSMCO_MAC_ENABLE;
+	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
+
+	for (i = 1000; i; i--) {
+		val16 = rtl8xxxu_read16(priv, REG_APS_FSMCO);
+		if (!(val16 & APS_FSMCO_MAC_ENABLE))
+			break;
+	}
+	if (!i) {
+		pr_info("%s: FSMCO_MAC_ENABLE poll failed\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Enable radio, GPIO, LED
+	 */
+	val16 = APS_FSMCO_HW_SUSPEND | APS_FSMCO_ENABLE_POWERDOWN |
+		APS_FSMCO_PFM_ALDN;
+	rtl8xxxu_write16(priv, REG_APS_FSMCO, val16);
+
+	/*
+	 * Release RF digital isolation
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_ISO_CTRL);
+	val16 &= ~SYS_ISO_DIOR;
+	rtl8xxxu_write16(priv, REG_SYS_ISO_CTRL, val16);
+
+	val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
+	val8 &= ~APSD_CTRL_OFF;
+	rtl8xxxu_write8(priv, REG_APSD_CTRL, val8);
+	for (i = 200; i; i--) {
+		val8 = rtl8xxxu_read8(priv, REG_APSD_CTRL);
+		if (!(val8 & APSD_CTRL_OFF_STATUS))
+			break;
+	}
+
+	if (!i) {
+		pr_info("%s: APSD_CTRL poll failed\n", __func__);
+		return -EBUSY;
+	}
+
+	/*
+	 * Enable MAC DMA/WMAC/SCHEDULE/SEC block
+	 */
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= CR_HCI_TXDMA_ENABLE | CR_HCI_RXDMA_ENABLE |
+		CR_TXDMA_ENABLE | CR_RXDMA_ENABLE | CR_PROTOCOL_ENABLE |
+		CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE;
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	/*
+	 * Workaround for 8188RU LNA power leakage problem.
+	 */
+	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
+		val32 &= ~BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
+	}
+	return 0;
+}
+
+static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv)
+{
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+	/*
+	 * Workaround for 8188RU LNA power leakage problem.
+	 */
+	if (priv->rtlchip == 0x8188c && priv->hi_pa) {
+		val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
+		val32 |= BIT(1);
+		rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
+	}
+
+	rtl8xxxu_active_to_lps(priv);
+
+	/* Turn off RF */
+	rtl8xxxu_write8(priv, REG_RF_CTRL, 0x00);
+
+	/* Reset Firmware if running in RAM */
+	if (rtl8xxxu_read8(priv, REG_MCU_FW_DL) & MCU_FW_RAM_SEL)
+		rtl8xxxu_firmware_self_reset(priv);
+
+	/* Reset MCU */
+	val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+	val16 &= ~SYS_FUNC_CPU_ENABLE;
+	rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+
+	/* Reset MCU ready status */
+	rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
+
+	rtl8xxxu_active_to_emu(priv);
+	rtl8xxxu_emu_to_disabled(priv);
+
+	/* Reset MCU IO Wrapper */
+	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+	val8 &= ~BIT(0);
+	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+
+	val8 = rtl8xxxu_read8(priv, REG_RSV_CTRL + 1);
+	val8 |= BIT(0);
+	rtl8xxxu_write8(priv, REG_RSV_CTRL + 1, val8);
+
+	/* RSV_CTRL 0x1C[7:0] = 0x0e  lock ISO/CLK/Power control register */
+	rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e);
+}
+
+static void rtl8xxxu_init_bt(struct rtl8xxxu_priv *priv)
+{
+	if (!priv->has_bluetooth)
+		return;
+}
+
+static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	struct rtl8xxxu_rfregval *rftable;
+	bool macpower;
+	int ret;
+	u8 val8;
+	u16 val16;
+	u32 val32;
+
+	/* Check if MAC is already powered on */
+	val8 = rtl8xxxu_read8(priv, REG_CR);
+
+	/*
+	 * Fix 92DU-VC S3 hang with the reason is that secondary mac is not
+	 * initialized. First MAC returns 0xea, second MAC returns 0x00
+	 */
+	if (val8 == 0xea)
+		macpower = false;
+	else
+		macpower = true;
+
+	ret = priv->fops->power_on(priv);
+	if (ret < 0) {
+		dev_warn(dev, "%s: Failed power on\n", __func__);
+		goto exit;
+	}
+
+	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+	if (!macpower) {
+		ret = rtl8xxxu_init_llt_table(priv, TX_TOTAL_PAGE_NUM);
+		if (ret) {
+			dev_warn(dev, "%s: LLT table init failed\n", __func__);
+			goto exit;
+		}
+	}
+
+	ret = rtl8xxxu_download_firmware(priv);
+	dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+	ret = rtl8xxxu_start_firmware(priv);
+	dev_dbg(dev, "%s: start_fiwmare %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table);
+	dev_dbg(dev, "%s: init_mac %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_init_phy_bb(priv);
+	dev_dbg(dev, "%s: init_phy_bb %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	switch(priv->rtlchip) {
+	case 0x8723a:
+		rftable = rtl8723au_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8188c:
+		if (priv->hi_pa)
+			rftable = rtl8188ru_radioa_1t_highpa_table;
+		else
+			rftable = rtl8192cu_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8191c:
+		rftable = rtl8192cu_radioa_1t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		break;
+	case 0x8192c:
+		rftable = rtl8192cu_radioa_2t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+		if (ret)
+			break;
+		rftable = rtl8192cu_radiob_2t_init_table;
+		ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret)
+		goto exit;
+
+	/* Reduce 80M spur */
+	rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
+	rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+
+	/* RFSW Control - clear bit 14 ?? */
+	rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003);
+	/* 0x07000760 */
+	val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW |
+		FPGA0_RF_ANTSWB | FPGA0_RF_PAPE |
+		((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE) <<
+		 FPGA0_RF_BD_CTRL_SHIFT);
+	rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+	/* 0x860[6:5]= 00 - why? - this sets antenna B */
+	rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66F60210);
+
+	priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A,
+						  RF6052_REG_MODE_AG);
+
+	dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+	if (!macpower) {
+		if (priv->ep_tx_normal_queue)
+			val8 = TX_PAGE_NUM_NORM_PQ;
+		else
+			val8 = 0;
+
+		rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8);
+
+		val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD;
+
+		if (priv->ep_tx_high_queue)
+			val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT);
+		if (priv->ep_tx_low_queue)
+			val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT);
+
+		rtl8xxxu_write32(priv, REG_RQPN, val32);
+
+		/*
+		 * Set TX buffer boundary
+		 */
+		val8 = TX_TOTAL_PAGE_NUM + 1;
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_BCNQ_BDNY, val8);
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_MGQ_BDNY, val8);
+		rtl8xxxu_write8(priv, REG_TXPKTBUF_WMAC_LBK_BF_HD, val8);
+		rtl8xxxu_write8(priv, REG_TRXFF_BNDY, val8);
+		rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8);
+	}
+
+	ret = rtl8xxxu_init_queue_priority(priv);
+	dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret);
+	if (ret)
+		goto exit;
+
+	/*
+	 * Set RX page boundary
+	 */
+	rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff);
+	/*
+	 * Transfer page size is always 128
+	 */
+	val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) |
+		(PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT);
+	rtl8xxxu_write8(priv, REG_PBP, val8);
+
+	/*
+	 * Unit in 8 bytes, not obvious what it is used for
+	 */
+	rtl8xxxu_write8(priv, REG_RX_DRVINFO_SZ, 4);
+
+	/*
+	 * Enable all interrupts - not obvious USB needs to do this
+	 */
+	rtl8xxxu_write32(priv, REG_HISR, 0xffffffff);
+	rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
+
+	rtl8xxxu_set_mac(priv);
+	rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION);
+
+	/*
+	 * Configure initial WMAC settings
+	 */
+	val32 = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_MCAST | RCR_ACCEPT_BCAST |
+		/* RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON | */
+		RCR_ACCEPT_MGMT_FRAME | RCR_HTC_LOC_CTRL |
+		RCR_APPEND_PHYSTAT | RCR_APPEND_ICV | RCR_APPEND_MIC;
+	rtl8xxxu_write32(priv, REG_RCR, val32);
+
+	/*
+	 * Accept all multicast
+	 */
+	rtl8xxxu_write32(priv, REG_MAR, 0xffffffff);
+	rtl8xxxu_write32(priv, REG_MAR + 4, 0xffffffff);
+
+	/*
+	 * Init adaptive controls
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
+	val32 |= RESPONSE_RATE_RRSR_CCK_ONLY_1M;
+	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+	/* CCK = 0x0a, OFDM = 0x10 */
+	rtl8xxxu_set_spec_sifs(priv, 0x10, 0x10);
+	rtl8xxxu_set_retry(priv, 0x30, 0x30);
+	rtl8xxxu_set_spec_sifs(priv, 0x0a, 0x10);
+
+	/*
+	 * Init EDCA
+	 */
+	rtl8xxxu_write16(priv, REG_MAC_SPEC_SIFS, 0x100a);
+
+	/* Set CCK SIFS */
+	rtl8xxxu_write16(priv, REG_SIFS_CCK, 0x100a);
+
+	/* Set OFDM SIFS */
+	rtl8xxxu_write16(priv, REG_SIFS_OFDM, 0x100a);
+
+	/* TXOP */
+	rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, 0x005ea42b);
+	rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, 0x0000a44f);
+	rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, 0x005ea324);
+	rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, 0x002fa226);
+
+	/* Set data auto rate fallback retry count */
+	rtl8xxxu_write32(priv, REG_DARFRC, 0x00000000);
+	rtl8xxxu_write32(priv, REG_DARFRC + 4, 0x10080404);
+	rtl8xxxu_write32(priv, REG_RARFRC, 0x04030201);
+	rtl8xxxu_write32(priv, REG_RARFRC + 4, 0x08070605);
+
+	val8 = rtl8xxxu_read8(priv, REG_FWHW_TXQ_CTRL);
+	val8 |= FWHW_TXQ_CTRL_AMPDU_RETRY;
+	rtl8xxxu_write8(priv, REG_FWHW_TXQ_CTRL, val8);
+
+	/*  Set ACK timeout */
+	rtl8xxxu_write8(priv, REG_ACKTO, 0x40);
+
+	/*
+	 * Initialize beacon parameters
+	 */
+	val16 = BEACON_DISABLE_TSF_UPDATE | (BEACON_DISABLE_TSF_UPDATE << 8);
+	rtl8xxxu_write16(priv, REG_BEACON_CTRL, val16);
+	rtl8xxxu_write16(priv, REG_TBTT_PROHIBIT, 0x6404);
+	rtl8xxxu_write8(priv, REG_DRIVER_EARLY_INT, DRIVER_EARLY_INT_TIME);
+	rtl8xxxu_write8(priv, REG_BEACON_DMA_TIME, BEACON_DMA_ATIME_INT_TIME);
+	rtl8xxxu_write16(priv, REG_BEACON_TCFG, 0x660F);
+
+	/*
+	 * Enable CCK and OFDM block
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	val32 |= (FPGA_RF_MODE_CCK | FPGA_RF_MODE_OFDM);
+	rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+	/*
+	 * Invalidate all CAM entries - bit 30 is undocumented
+	 */
+	rtl8xxxu_write32(priv, REG_CAM_CMD, CAM_CMD_POLLING | BIT(30));
+
+	/*
+	 * Start out with default power levels for channel 6, 20MHz
+	 */
+	rtl8723a_set_tx_power(priv, 1, false);
+
+	/* Let the 8051 take control of antenna setting */
+	val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+	val8 |= LEDCFG2_DPDT_SELECT;
+	rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+
+	rtl8xxxu_write8(priv, REG_HWSEQ_CTRL, 0xff);
+
+	/* Disable BAR - not sure if this has any effect on USB */
+	rtl8xxxu_write32(priv, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+	rtl8xxxu_write16(priv, REG_FAST_EDCA_CTRL, 0);
+
+	/*
+	 * Not sure if we should get into this at all
+	 */
+	if (priv->iqk_initialized) {
+		rtl8xxxu_restore_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+				      priv->bb_recovery_backup,
+				      RTL8XXXU_BB_REGS);
+	} else {
+		rtl8723a_phy_iq_calibrate(priv);
+		priv->iqk_initialized = true;
+	}
+
+	/*
+	 * This should enable thermal meter
+	 */
+	rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_T_METER, 0x60);
+
+	rtl8723a_phy_lc_calibrate(priv);
+
+	/* fix USB interface interference issue */
+	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+	rtl8xxxu_write8(priv, 0xfe41, 0x8d);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+	rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320);
+
+	/* Solve too many protocol error on USB bus */
+	/* Can't do this for 8188/8192 UMC A cut parts */
+	rtl8xxxu_write8(priv, 0xfe40, 0xe6);
+	rtl8xxxu_write8(priv, 0xfe41, 0x94);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+	rtl8xxxu_write8(priv, 0xfe41, 0x19);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe5);
+	rtl8xxxu_write8(priv, 0xfe41, 0x91);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	rtl8xxxu_write8(priv, 0xfe40, 0xe2);
+	rtl8xxxu_write8(priv, 0xfe41, 0x81);
+	rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+	/* Init BT hw config. */
+	rtl8xxxu_init_bt(priv);
+
+	/*
+	 * Not sure if we really need to save these parameters, but the
+	 * vendor driver does
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM2);
+	if (val32 & FPGA0_HSSI_PARM2_CCK_HIGH_PWR)
+		priv->path_a_hi_power = 1;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+	priv->path_a_rf_paths = val32 & OFDM_RF_PATH_RX_MASK;
+
+	val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1);
+	priv->path_a_ig_value = val32 & OFDM0_X_AGC_CORE1_IGI_MASK;
+
+	/* Set NAV_UPPER to 30000us */
+	val8 = ((30000 + NAV_UPPER_UNIT - 1) / NAV_UPPER_UNIT);
+	rtl8xxxu_write8(priv, REG_NAV_UPPER, val8);
+
+	/*
+	 * 2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test,
+	 * but we need to fin root cause.
+	 */
+	val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+	if ((val32 & 0xff000000) != 0x83000000) {
+		val32 |= FPGA_RF_MODE_CCK;
+		rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL);
+	val32 |= FWHW_TXQ_CTRL_XMIT_MGMT_ACK;
+	/* ack for xmit mgmt frames. */
+	rtl8xxxu_write32(priv, REG_FWHW_TXQ_CTRL, val32);
+
+exit:
+	return ret;
+}
+
+static void rtl8xxxu_disable_device(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	rtl8xxxu_power_off(priv);
+}
+
+static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv,
+			       struct ieee80211_key_conf *key, const u8 *mac)
+{
+	u32 cmd, val32, addr, ctrl;
+	int j, i, tmp_debug;
+
+	tmp_debug = rtl8xxxu_debug;
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_KEY)
+		rtl8xxxu_debug |= RTL8XXXU_DEBUG_REG_WRITE;
+
+	/*
+	 * This is a bit of a hack - the lower bits of the cipher
+	 * suite selector happens to match the cipher index in the CAM
+	 */
+	addr = key->keyidx << CAM_CMD_KEY_SHIFT;
+	ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID;
+
+	for (j = 5; j >= 0; j--) {
+		switch (j) {
+		case 0:
+			val32 = ctrl | (mac[0] << 16) | (mac[1] << 24);
+			break;
+		case 1:
+			val32 = mac[2] | (mac[3] << 8) |
+				(mac[4] << 16) | (mac[5] << 24);
+			break;
+		default:
+			i = (j - 2) << 2;
+			val32 = key->key[i] | (key->key[i + 1] << 8) |
+				key->key[i + 2] << 16 | key->key[i + 3] << 24;
+			break;
+		}
+
+		rtl8xxxu_write32(priv, REG_CAM_WRITE, val32);
+		cmd = CAM_CMD_POLLING | CAM_CMD_WRITE | (addr + j);
+		rtl8xxxu_write32(priv, REG_CAM_CMD, cmd);
+		udelay(100);
+	}
+
+	rtl8xxxu_debug = tmp_debug;
+}
+
+static void rtl8xxxu_sw_scan_start(struct ieee80211_hw *hw,
+				   struct ieee80211_vif *vif, const u8* mac)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+	val8 |= BEACON_DISABLE_TSF_UPDATE;
+	rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+}
+
+static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	u8 val8;
+
+	val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+	val8 &= ~BEACON_DISABLE_TSF_UPDATE;
+	rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+}
+
+static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv,
+				      u32 ramask, int sgi)
+{
+	struct h2c_cmd h2c;
+
+	h2c.ramask.cmd = H2C_SET_RATE_MASK;
+	h2c.ramask.mask_lo = cpu_to_le16(ramask & 0xffff);
+	h2c.ramask.mask_hi = cpu_to_le16(ramask >> 16);
+
+	h2c.ramask.arg = 0x80;
+	if (sgi)
+		h2c.ramask.arg |= 0x20;
+
+	dev_dbg(&priv->udev->dev, "%s: rate mask %08x, arg %02x\n", __func__,
+		ramask, h2c.ramask.arg);
+	rtl8723a_h2c_cmd(priv, &h2c);
+}
+
+static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg)
+{
+	u32 val32;
+	u8 rate_idx = 0;
+
+	rate_cfg &= RESPONSE_RATE_BITMAP_ALL;
+
+	val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+	val32 &= ~RESPONSE_RATE_BITMAP_ALL;
+	val32 |= rate_cfg;
+	rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+
+	dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__,	rate_cfg);
+
+	while (rate_cfg) {
+		rate_cfg = (rate_cfg >> 1);
+		rate_idx++;
+	}
+	rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx);
+}
+
+static void
+rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			  struct ieee80211_bss_conf *bss_conf, u32 changed)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	struct ieee80211_sta *sta;
+	u32 val32;
+	u8 val8;
+
+	if (changed & BSS_CHANGED_ASSOC) {
+		struct h2c_cmd h2c;
+
+		dev_dbg(dev, "Changed ASSOC: %i!\n", bss_conf->assoc);
+
+		memset(&h2c, 0, sizeof(struct h2c_cmd));
+		rtl8xxxu_set_linktype(priv, vif->type);
+
+		if (bss_conf->assoc) {
+			u32 ramask;
+			int sgi = 0;
+
+			rcu_read_lock();
+			sta = ieee80211_find_sta(vif, bss_conf->bssid);
+			if (!sta) {
+				dev_info(dev, "%s: ASSOC no sta found\n",
+					 __func__);
+				rcu_read_unlock();
+				goto error;
+			}
+
+			if (sta->ht_cap.ht_supported)
+				dev_info(dev, "%s: HT supported\n", __func__);
+			if (sta->vht_cap.vht_supported)
+				dev_info(dev, "%s: VHT supported\n", __func__);
+
+			/* TODO: Set bits 28-31 for rate adaptive id */
+			ramask = (sta->supp_rates[0] & 0xfff) |
+				sta->ht_cap.mcs.rx_mask[0] << 12 |
+				sta->ht_cap.mcs.rx_mask[1] << 20;
+			if (sta->ht_cap.cap &
+			    (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))
+				sgi = 1;
+			rcu_read_unlock();
+
+			rtl8xxxu_update_rate_mask(priv, ramask, sgi);
+
+			val32 = rtl8xxxu_read32(priv, REG_RCR);
+			val32 |= RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON;
+			rtl8xxxu_write32(priv, REG_RCR, val32);
+
+			/* Enable RX of data frames */
+			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0xffff);
+
+			rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff);
+
+			rtl8723a_stop_tx_beacon(priv);
+
+			/* joinbss sequence */
+			rtl8xxxu_write16(priv, REG_BCN_PSR_RPT,
+					 0xc000 | bss_conf->aid);
+
+			h2c.joinbss.data = H2C_JOIN_BSS_CONNECT;
+		} else {
+			val32 = rtl8xxxu_read32(priv, REG_RCR);
+			val32 &= ~(RCR_CHECK_BSSID_MATCH |
+				   RCR_CHECK_BSSID_BEACON);
+			rtl8xxxu_write32(priv, REG_RCR, val32);
+
+			val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+			val8 |= BEACON_DISABLE_TSF_UPDATE;
+			rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+
+			/* Disable RX of data frames */
+			rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+			h2c.joinbss.data = H2C_JOIN_BSS_DISCONNECT;
+		}
+		h2c.joinbss.cmd = H2C_JOIN_BSS_REPORT;
+		rtl8723a_h2c_cmd(priv, &h2c);
+	}
+
+	if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+		dev_dbg(dev, "Changed ERP_PREAMBLE: Use short preamble %i\n",
+			bss_conf->use_short_preamble);
+		val32 = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET);
+		if (bss_conf->use_short_preamble)
+			val32 |= RSR_ACK_SHORT_PREAMBLE;
+		else
+			val32 &= ~RSR_ACK_SHORT_PREAMBLE;
+		rtl8xxxu_write32(priv, REG_RESPONSE_RATE_SET, val32);
+	}
+
+	if (changed & BSS_CHANGED_ERP_SLOT) {
+		dev_dbg(dev, "Changed ERP_SLOT: short_slot_time %i\n",
+			bss_conf->use_short_slot);
+
+		if (bss_conf->use_short_slot)
+			val8 = 9;
+		else
+			val8 = 20;
+		rtl8xxxu_write8(priv, REG_SLOT, val8);
+	}
+
+	if (changed & BSS_CHANGED_BSSID) {
+		dev_dbg(dev, "Changed BSSID!\n");
+		rtl8xxxu_set_bssid(priv, bss_conf->bssid);
+	}
+
+	if (changed & BSS_CHANGED_BASIC_RATES) {
+		dev_dbg(dev, "Changed BASIC_RATES!\n");
+		rtl8xxxu_set_basic_rates(priv, bss_conf->basic_rates);
+	}
+error:
+	return;
+}
+
+static u32 rtl8xxxu_80211_to_rtl_queue(u32 queue)
+{
+	u32 rtlqueue;
+
+	switch (queue) {
+	case IEEE80211_AC_VO:
+		rtlqueue = TXDESC_QUEUE_VO;
+		break;
+	case IEEE80211_AC_VI:
+		rtlqueue = TXDESC_QUEUE_VI;
+		break;
+	case IEEE80211_AC_BE:
+		rtlqueue = TXDESC_QUEUE_BE;
+		break;
+	case IEEE80211_AC_BK:
+		rtlqueue = TXDESC_QUEUE_BK;
+		break;
+	default:
+		rtlqueue = TXDESC_QUEUE_BE;
+	}
+
+	return rtlqueue;
+}
+
+static u32 rtl8xxxu_queue_select(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	u32 queue;
+
+	if (ieee80211_is_mgmt(hdr->frame_control))
+		queue = TXDESC_QUEUE_MGNT;
+	else
+		queue = rtl8xxxu_80211_to_rtl_queue(skb_get_queue_mapping(skb));
+
+	return queue;
+}
+
+static void rtl8xxxu_calc_tx_desc_csum(struct rtl8xxxu_tx_desc *tx_desc)
+{
+	__le16 *ptr = (__le16 *)tx_desc;
+	u16 csum = 0;
+	int i;
+
+	/*
+	 * Clear csum field before calculation, as the csum field is
+	 * in the middle of the struct.
+	 */
+	tx_desc->csum = cpu_to_le16(0);
+
+	for (i = 0; i < (sizeof(struct rtl8xxxu_tx_desc) / sizeof(u16)); i++)
+		csum = csum ^ le16_to_cpu(ptr[i]);
+
+	tx_desc->csum |= cpu_to_le16(csum);
+}
+
+static void rtl8xxxu_free_tx_resources(struct rtl8xxxu_priv *priv)
+{
+	struct rtl8xxxu_tx_urb *tx_urb, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_urb_lock, flags);
+	list_for_each_entry_safe(tx_urb, tmp, &priv->tx_urb_free_list, list) {
+		list_del(&tx_urb->list);
+		priv->tx_urb_free_count--;
+		usb_free_urb(&tx_urb->urb);
+	}
+	spin_unlock_irqrestore(&priv->tx_urb_lock, flags);
+}
+
+static struct rtl8xxxu_tx_urb *
+rtl8xxxu_alloc_tx_urb(struct rtl8xxxu_priv *priv)
+{
+	struct rtl8xxxu_tx_urb *tx_urb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->tx_urb_lock, flags);
+	tx_urb = list_first_entry_or_null(&priv->tx_urb_free_list,
+					  struct rtl8xxxu_tx_urb, list);
+	if (tx_urb) {
+		list_del(&tx_urb->list);
+		priv->tx_urb_free_count--;
+		if (priv->tx_urb_free_count < RTL8XXXU_TX_URB_LOW_WATER &&
+		    !priv->tx_stopped) {
+			priv->tx_stopped = true;
+			ieee80211_stop_queues(priv->hw);
+		}
+	}
+
+	spin_unlock_irqrestore(&priv->tx_urb_lock, flags);
+
+	return tx_urb;
+}
+
+static void rtl8xxxu_free_tx_urb(struct rtl8xxxu_priv *priv,
+				 struct rtl8xxxu_tx_urb *tx_urb)
+{
+	unsigned long flags;
+
+	INIT_LIST_HEAD(&tx_urb->list);
+
+	spin_lock_irqsave(&priv->tx_urb_lock, flags);
+
+	list_add(&tx_urb->list, &priv->tx_urb_free_list);
+	priv->tx_urb_free_count++;
+	if (priv->tx_urb_free_count > RTL8XXXU_TX_URB_HIGH_WATER &&
+	    priv->tx_stopped) {
+		priv->tx_stopped = false;
+		ieee80211_wake_queues(priv->hw);
+	}
+
+	spin_unlock_irqrestore(&priv->tx_urb_lock, flags);
+}
+
+static void rtl8xxxu_tx_complete(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct ieee80211_tx_info *tx_info;
+	struct ieee80211_hw *hw;
+	struct rtl8xxxu_tx_urb *tx_urb =
+		container_of(urb, struct rtl8xxxu_tx_urb, urb);
+
+	tx_info = IEEE80211_SKB_CB(skb);
+	hw = tx_info->rate_driver_data[0];
+
+	skb_pull(skb, sizeof(struct rtl8xxxu_tx_desc));
+
+	ieee80211_tx_info_clear_status(tx_info);
+	tx_info->status.rates[0].idx = -1;
+	tx_info->status.rates[0].count = 0;
+
+	if (!urb->status)
+		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+	ieee80211_tx_status_irqsafe(hw, skb);
+
+	rtl8xxxu_free_tx_urb(hw->priv, tx_urb);
+}
+
+static void rtl8xxxu_dump_action(struct device *dev,
+				 struct ieee80211_hdr *hdr)
+{
+	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr;
+	u16 cap, timeout;
+
+	if (!(rtl8xxxu_debug & RTL8XXXU_DEBUG_ACTION))
+		return;
+
+	switch (mgmt->u.action.u.addba_resp.action_code) {
+	case WLAN_ACTION_ADDBA_RESP:
+		cap = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+		timeout = le16_to_cpu(mgmt->u.action.u.addba_resp.timeout);
+		dev_info(dev, "WLAN_ACTION_ADDBA_RESP: "
+			 "timeout %i, tid %02x, buf_size %02x, policy %02x, "
+			 "status %02x\n",
+			 timeout,
+			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
+			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
+			 (cap >> 1) & 0x1,
+			 le16_to_cpu(mgmt->u.action.u.addba_resp.status));
+		break;
+	case WLAN_ACTION_ADDBA_REQ:
+		cap = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+		timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout);
+		dev_info(dev, "WLAN_ACTION_ADDBA_REQ: "
+			 "timeout %i, tid %02x, buf_size %02x, policy %02x\n",
+			 timeout,
+			 (cap & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2,
+			 (cap & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6,
+			 (cap >> 1) & 0x1);
+		break;
+	default:
+		dev_info(dev, "action frame %02x\n",
+			 mgmt->u.action.u.addba_resp.action_code);
+		break;
+	}
+}
+
+static void rtl8xxxu_tx(struct ieee80211_hw *hw,
+			struct ieee80211_tx_control *control,
+			struct sk_buff *skb)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct rtl8xxxu_tx_desc *tx_desc;
+	struct rtl8xxxu_tx_urb *tx_urb;
+	struct ieee80211_sta *sta = NULL;
+	struct ieee80211_vif *vif = tx_info->control.vif;
+	struct device *dev = &priv->udev->dev;
+	u32 queue, rate;
+	u16 pktlen = skb->len;
+	u16 seq_number;
+	u16 rate_flag = tx_info->control.rates[0].flags;
+	int ret;
+
+	if (skb_headroom(skb) < sizeof(struct rtl8xxxu_tx_desc)) {
+		dev_warn(dev,
+			 "%s: Not enough headroom (%i) for tx descriptor\n",
+			 __func__, skb_headroom(skb));
+		goto error;
+	}
+
+	if (unlikely(skb->len > (65535 - sizeof(struct rtl8xxxu_tx_desc)))) {
+		dev_warn(dev, "%s: Trying to send over-sized skb (%i)\n",
+			 __func__, skb->len);
+		goto error;
+	}
+
+	tx_urb = rtl8xxxu_alloc_tx_urb(priv);
+	if (!tx_urb) {
+		dev_warn(dev, "%s: Unable to allocate tx urb\n", __func__);
+		goto error;
+	}
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_TX)
+		dev_info(dev, "%s: TX rate: %d (%d), pkt size %d\n",
+			 __func__, tx_rate->bitrate, tx_rate->hw_value, pktlen);
+
+	if (ieee80211_is_action(hdr->frame_control))
+		rtl8xxxu_dump_action(dev, hdr);
+
+	tx_info->rate_driver_data[0] = hw;
+
+	if (control && control->sta)
+		sta = control->sta;
+
+	tx_desc = (struct rtl8xxxu_tx_desc *)
+		skb_push(skb, sizeof(struct rtl8xxxu_tx_desc));
+
+	memset(tx_desc, 0, sizeof(struct rtl8xxxu_tx_desc));
+	tx_desc->pkt_size = cpu_to_le16(pktlen);
+	tx_desc->pkt_offset = sizeof(struct rtl8xxxu_tx_desc);
+
+	tx_desc->txdw0 =
+		TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT;
+	if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+	    is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
+		tx_desc->txdw0 |= TXDESC_BROADMULTICAST;
+
+	queue = rtl8xxxu_queue_select(hw, skb);
+	tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT);
+
+	if (tx_info->control.hw_key) {
+		switch (tx_info->control.hw_key->cipher) {
+		case WLAN_CIPHER_SUITE_WEP40:
+		case WLAN_CIPHER_SUITE_WEP104:
+		case WLAN_CIPHER_SUITE_TKIP:
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_RC4);
+			break;
+		case WLAN_CIPHER_SUITE_CCMP:
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_SEC_AES);
+			break;
+		default:
+			break;
+		}
+	}
+
+	seq_number = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+	tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC_SEQ_SHIFT);
+
+	if (rate_flag & IEEE80211_TX_RC_MCS)
+		rate = tx_info->control.rates[0].idx + DESC_RATE_MCS0;
+	else
+		rate = tx_rate->hw_value;
+	tx_desc->txdw5 = cpu_to_le32(rate);
+
+	if (ieee80211_is_data(hdr->frame_control))
+		tx_desc->txdw5 |= cpu_to_le32(0x0001ff00);
+
+	/* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */
+	if (ieee80211_is_data_qos(hdr->frame_control) && sta) {
+		if (sta->ht_cap.ht_supported) {
+			u32 ampdu, val32;
+
+			ampdu = (u32)sta->ht_cap.ampdu_density;
+			val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;
+			tx_desc->txdw2 |= cpu_to_le32(val32);
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_AGG_ENABLE);
+		} else
+			tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
+	} else
+		tx_desc->txdw1 |= cpu_to_le32(TXDESC_BK);
+
+	if (ieee80211_is_data_qos(hdr->frame_control))
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_QOS);
+	if (rate_flag & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ||
+	    (sta && vif && vif->bss_conf.use_short_preamble))
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_SHORT_PREAMBLE);
+	if (rate_flag & IEEE80211_TX_RC_SHORT_GI ||
+	    (ieee80211_is_data_qos(hdr->frame_control) &&
+	     sta && sta->ht_cap.cap &
+	     (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20))) {
+		tx_desc->txdw5 |= cpu_to_le32(TXDESC_SHORT_GI);
+	}
+	if (ieee80211_is_mgmt(hdr->frame_control)) {
+		tx_desc->txdw5 = cpu_to_le32(tx_rate->hw_value);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_USE_DRIVER_RATE);
+		tx_desc->txdw5 |= cpu_to_le32(6 << TXDESC_RETRY_LIMIT_SHIFT);
+		tx_desc->txdw5 |= cpu_to_le32(TXDESC_RETRY_LIMIT_ENABLE);
+	}
+
+	if (rate_flag & IEEE80211_TX_RC_USE_RTS_CTS) {
+		/* Use RTS rate 24M - does the mac80211 tell us which to use? */
+		tx_desc->txdw4 |= cpu_to_le32(DESC_RATE_24M);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_RTS_CTS_ENABLE);
+		tx_desc->txdw4 |= cpu_to_le32(TXDESC_HW_RTS_ENABLE);
+	}
+
+	rtl8xxxu_calc_tx_desc_csum(tx_desc);
+
+	usb_fill_bulk_urb(&tx_urb->urb, priv->udev, priv->pipe_out[queue],
+			  skb->data, skb->len, rtl8xxxu_tx_complete, skb);
+
+	usb_anchor_urb(&tx_urb->urb, &priv->tx_anchor);
+	ret = usb_submit_urb(&tx_urb->urb, GFP_ATOMIC);
+	if (ret) {
+		usb_unanchor_urb(&tx_urb->urb);
+		rtl8xxxu_free_tx_urb(priv, tx_urb);
+		goto error;
+	}
+	return;
+error:
+	dev_kfree_skb(skb);
+}
+
+static void rtl8xxxu_rx_parse_phystats(struct rtl8xxxu_priv *priv,
+				       struct ieee80211_rx_status *rx_status,
+				       struct rtl8xxxu_rx_desc *rx_desc,
+				       struct rtl8723au_phy_stats *phy_stats)
+{
+	if (phy_stats->sgi_en)
+		rx_status->flag |= RX_FLAG_SHORT_GI;
+
+	if (rx_desc->rxmcs < DESC_RATE_6M) {
+		/*
+		 * Handle PHY stats for CCK rates
+		 */
+		u8 cck_agc_rpt = phy_stats->cck_agc_rpt_ofdm_cfosho_a;
+
+		switch (cck_agc_rpt & 0xc0) {
+		case 0xc0:
+			rx_status->signal = -46 - (cck_agc_rpt & 0x3e);
+			break;
+		case 0x80:
+			rx_status->signal = -26 - (cck_agc_rpt & 0x3e);
+			break;
+		case 0x40:
+			rx_status->signal = -12 - (cck_agc_rpt & 0x3e);
+			break;
+		case 0x00:
+			rx_status->signal = 16 - (cck_agc_rpt & 0x3e);
+			break;
+		}
+	} else {
+		rx_status->signal =
+			(phy_stats->cck_sig_qual_ofdm_pwdb_all >> 1) - 110;
+	}
+}
+
+static void rtl8xxxu_free_rx_resources(struct rtl8xxxu_priv *priv)
+{
+	struct rtl8xxxu_rx_urb *rx_urb, *tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->rx_urb_lock, flags);
+
+	list_for_each_entry_safe(rx_urb, tmp,
+				 &priv->rx_urb_pending_list, list) {
+		list_del(&rx_urb->list);
+		priv->rx_urb_pending_count--;
+		usb_free_urb(&rx_urb->urb);
+	}
+
+	spin_unlock_irqrestore(&priv->rx_urb_lock, flags);
+}
+
+static void rtl8xxxu_queue_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+	int pending = 0;
+
+	spin_lock_irqsave(&priv->rx_urb_lock, flags);
+
+	if (!priv->shutdown) {
+		list_add_tail(&rx_urb->list, &priv->rx_urb_pending_list);
+		priv->rx_urb_pending_count++;
+		pending = priv->rx_urb_pending_count;
+	} else {
+		skb = (struct sk_buff *)rx_urb->urb.context;
+		dev_kfree_skb(skb);
+		usb_free_urb(&rx_urb->urb);
+	}
+
+	spin_unlock_irqrestore(&priv->rx_urb_lock, flags);
+
+	if (pending > RTL8XXXU_RX_URB_PENDING_WATER)
+		schedule_work(&priv->rx_urb_wq);
+}
+
+static void rtl8xxxu_rx_urb_work(struct work_struct *work)
+{
+	struct rtl8xxxu_priv *priv;
+	struct rtl8xxxu_rx_urb *rx_urb, *tmp;
+	struct list_head local;
+	struct sk_buff *skb;
+	unsigned long flags;
+	int ret;
+
+	priv = container_of(work, struct rtl8xxxu_priv, rx_urb_wq);
+	INIT_LIST_HEAD(&local);
+
+	spin_lock_irqsave(&priv->rx_urb_lock, flags);
+
+	list_splice_init(&priv->rx_urb_pending_list, &local);
+	priv->rx_urb_pending_count = 0;
+
+	spin_unlock_irqrestore(&priv->rx_urb_lock, flags);
+
+	list_for_each_entry_safe(rx_urb, tmp, &local, list) {
+		list_del_init(&rx_urb->list);
+		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+		/*
+		 * If out of memory or temporary error, put it back on the
+		 * queue and try again. Otherwise the device is dead/gone
+		 * and we should drop it.
+		 */
+		switch (ret) {
+		case 0:
+			break;
+		case -ENOMEM:
+		case -EAGAIN:
+			rtl8xxxu_queue_rx_urb(priv, rx_urb);
+			break;
+		default:
+			pr_info("failed to requeue urb %i\n", ret);
+			skb = (struct sk_buff *)rx_urb->urb.context;
+			dev_kfree_skb(skb);
+			usb_free_urb(&rx_urb->urb);
+		}
+	}
+}
+
+static void rtl8xxxu_rx_complete(struct urb *urb)
+{
+	struct rtl8xxxu_rx_urb *rx_urb =
+		container_of(urb, struct rtl8xxxu_rx_urb, urb);
+	struct ieee80211_hw *hw = rx_urb->hw;
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct sk_buff *skb = (struct sk_buff *)urb->context;
+	struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data;
+	struct rtl8723au_phy_stats *phy_stats;
+	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+	struct ieee80211_mgmt *mgmt;
+	struct device *dev = &priv->udev->dev;
+	__le32 *_rx_desc_le = (__le32 *)skb->data;
+	u32 *_rx_desc = (u32 *)skb->data;
+	int cnt, len, drvinfo_sz, desc_shift, i;
+
+	for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++)
+		_rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
+
+	cnt = rx_desc->frag;
+	len = rx_desc->pktlen;
+	drvinfo_sz = rx_desc->drvinfo_sz * 8;
+	desc_shift = rx_desc->shift;
+	skb_put(skb, urb->actual_length);
+
+	if (urb->status == 0) {
+		skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc));
+		phy_stats = (struct rtl8723au_phy_stats *)skb->data;
+
+		skb_pull(skb, drvinfo_sz + desc_shift);
+
+		mgmt = (struct ieee80211_mgmt *)skb->data;
+
+		memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+		if (rx_desc->phy_stats)
+			rtl8xxxu_rx_parse_phystats(priv, rx_status,
+						   rx_desc, phy_stats);
+
+		rx_status->freq = hw->conf.chandef.chan->center_freq;
+		rx_status->band = hw->conf.chandef.chan->band;
+
+		rx_status->mactime = le32_to_cpu(rx_desc->tsfl);
+		rx_status->flag |= RX_FLAG_MACTIME_START;
+
+		if (!rx_desc->swdec)
+			rx_status->flag |= RX_FLAG_DECRYPTED;
+		if (rx_desc->crc32)
+			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+		if (rx_desc->bw)
+			rx_status->flag |= RX_FLAG_40MHZ;
+
+		if (rx_desc->rxht) {
+			rx_status->flag |= RX_FLAG_HT;
+			rx_status->rate_idx = rx_desc->rxmcs - DESC_RATE_MCS0;
+		} else {
+			rx_status->rate_idx = rx_desc->rxmcs;
+		}
+
+		ieee80211_rx_irqsafe(hw, skb);
+		skb = NULL;
+		rx_urb->urb.context = NULL;
+		rtl8xxxu_queue_rx_urb(priv, rx_urb);
+	} else {
+		dev_dbg(dev, "%s: status %i\n",	__func__, urb->status);
+		goto cleanup;
+	}
+	return;
+
+cleanup:
+	usb_free_urb(urb);
+	dev_kfree_skb(skb);
+	return;
+}
+
+static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
+				  struct rtl8xxxu_rx_urb *rx_urb)
+{
+	struct sk_buff *skb;
+	int skb_size;
+	int ret;
+
+	skb_size = sizeof(struct rtl8xxxu_rx_desc) + RTL_RX_BUFFER_SIZE;
+	skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	memset(skb->data, 0, sizeof(struct rtl8xxxu_rx_desc));
+	usb_fill_bulk_urb(&rx_urb->urb, priv->udev, priv->pipe_in, skb->data,
+			  skb_size, rtl8xxxu_rx_complete, skb);
+	usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor);
+	ret = usb_submit_urb(&rx_urb->urb, GFP_ATOMIC);
+	if (ret)
+		usb_unanchor_urb(&rx_urb->urb);
+	return ret;
+}
+
+static void rtl8xxxu_int_complete(struct urb *urb)
+{
+	struct rtl8xxxu_priv *priv = (struct rtl8xxxu_priv *)urb->context;
+	struct device *dev = &priv->udev->dev;
+	int ret;
+
+	dev_dbg(dev, "%s: status %i\n", __func__, urb->status);
+	if (urb->status == 0) {
+		usb_anchor_urb(urb, &priv->int_anchor);
+		ret = usb_submit_urb(urb, GFP_ATOMIC);
+		if (ret)
+			usb_unanchor_urb(urb);
+	} else {
+		dev_info(dev, "%s: Error %i\n", __func__, urb->status);
+	}
+}
+
+
+static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct urb *urb;
+	u32 val32;
+	int ret;
+
+	urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!urb)
+		return -ENOMEM;
+
+	usb_fill_int_urb(urb, priv->udev, priv->pipe_interrupt,
+			 priv->int_buf, USB_INTR_CONTENT_LENGTH,
+			 rtl8xxxu_int_complete, priv, 1);
+	usb_anchor_urb(urb, &priv->int_anchor);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		goto error;
+	}
+
+	val32 = rtl8xxxu_read32(priv, REG_USB_HIMR);
+	val32 |= USB_HIMR_CPWM;
+	rtl8xxxu_write32(priv, REG_USB_HIMR, val32);
+
+error:
+	return ret;
+}
+
+static int rtl8xxxu_add_interface(struct ieee80211_hw *hw,
+				  struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	int ret;
+	u8 val8;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		rtl8723a_stop_tx_beacon(priv);
+
+		val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL);
+		val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE |
+			BEACON_DISABLE_TSF_UPDATE;
+		rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
+		ret = 0;
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	rtl8xxxu_set_linktype(priv, vif->type);
+
+	return ret;
+}
+
+static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw,
+				      struct ieee80211_vif *vif)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	dev_dbg(&priv->udev->dev, "%s\n", __func__);
+}
+
+static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u16 val16;
+	int ret = 0, channel;
+	bool ht40;
+
+	if (rtl8xxxu_debug & RTL8XXXU_DEBUG_CHANNEL)
+		dev_info(dev,
+			 "%s: channel: %i (changed %08x chandef.width %02x)\n",
+			 __func__, hw->conf.chandef.chan->hw_value,
+			 changed, hw->conf.chandef.width);
+
+	if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
+		val16 = ((hw->conf.long_frame_max_tx_count <<
+			  RETRY_LIMIT_LONG_SHIFT) & RETRY_LIMIT_LONG_MASK) |
+			((hw->conf.short_frame_max_tx_count <<
+			  RETRY_LIMIT_SHORT_SHIFT) & RETRY_LIMIT_SHORT_MASK);
+		rtl8xxxu_write16(priv, REG_RETRY_LIMIT, val16);
+	}
+
+	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+		switch (hw->conf.chandef.width) {
+		case NL80211_CHAN_WIDTH_20_NOHT:
+		case NL80211_CHAN_WIDTH_20:
+			ht40 = false;
+			break;
+		case NL80211_CHAN_WIDTH_40:
+			ht40 = true;
+			break;
+		default:
+			ret = -ENOTSUPP;
+			goto exit;
+		}
+
+		channel = hw->conf.chandef.chan->hw_value;
+
+		rtl8723a_set_tx_power(priv, channel, ht40);
+
+		rtl8723au_config_channel(hw);
+	}
+
+exit:
+	return ret;
+}
+
+static int rtl8xxxu_conf_tx(struct ieee80211_hw *hw,
+			    struct ieee80211_vif *vif, u16 queue,
+			    const struct ieee80211_tx_queue_params *param)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u32 val32;
+	u8 aifs, acm_ctrl, acm_bit;
+
+	aifs = param->aifs;
+
+	val32 = aifs |
+		fls(param->cw_min) << EDCA_PARAM_ECW_MIN_SHIFT |
+		fls(param->cw_max) << EDCA_PARAM_ECW_MAX_SHIFT |
+		(u32)param->txop << EDCA_PARAM_TXOP_SHIFT;
+
+	acm_ctrl = rtl8xxxu_read8(priv, REG_ACM_HW_CTRL);
+	dev_dbg(dev,
+		"%s: IEEE80211 queue %02x val %08x, acm %i, acm_ctrl %02x\n",
+		__func__, queue, val32, param->acm, acm_ctrl);
+
+	switch (queue) {
+	case IEEE80211_AC_VO:
+		acm_bit = ACM_HW_CTRL_VO;
+		rtl8xxxu_write32(priv, REG_EDCA_VO_PARAM, val32);
+		break;
+	case IEEE80211_AC_VI:
+		acm_bit = ACM_HW_CTRL_VI;
+		rtl8xxxu_write32(priv, REG_EDCA_VI_PARAM, val32);
+		break;
+	case IEEE80211_AC_BE:
+		acm_bit = ACM_HW_CTRL_BE;
+		rtl8xxxu_write32(priv, REG_EDCA_BE_PARAM, val32);
+		break;
+	case IEEE80211_AC_BK:
+		acm_bit = ACM_HW_CTRL_BK;
+		rtl8xxxu_write32(priv, REG_EDCA_BK_PARAM, val32);
+		break;
+	default:
+		acm_bit = 0;
+		break;
+	}
+
+	if (param->acm)
+		acm_ctrl |= acm_bit;
+	else
+		acm_ctrl &= ~acm_bit;
+	rtl8xxxu_write8(priv, REG_ACM_HW_CTRL, acm_ctrl);
+
+	return 0;
+}
+
+static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw,
+				      unsigned int changed_flags,
+				      unsigned int *total_flags, u64 multicast)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+
+	dev_dbg(&priv->udev->dev, "%s: changed_flags %08x, total_flags %08x\n",
+		__func__, changed_flags, *total_flags);
+
+	*total_flags &= (FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC);
+}
+
+static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts)
+{
+	if (rts > 2347)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			    struct ieee80211_vif *vif,
+			    struct ieee80211_sta *sta,
+			    struct ieee80211_key_conf *key)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u8 mac_addr[ETH_ALEN];
+	u8 val8;
+	u16 val16;
+	u32 val32;
+	int retval = -EOPNOTSUPP;
+
+	dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n",
+		__func__, cmd, key->cipher, key->keyidx);
+
+	if (vif->type != NL80211_IFTYPE_STATION)
+		return -EOPNOTSUPP;
+
+	if (key->keyidx > 3)
+		return -EOPNOTSUPP;
+
+	switch (key->cipher) {
+	case WLAN_CIPHER_SUITE_WEP40:
+	case WLAN_CIPHER_SUITE_WEP104:
+
+		break;
+	case WLAN_CIPHER_SUITE_CCMP:
+		key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+		break;
+	case WLAN_CIPHER_SUITE_TKIP:
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
+		dev_dbg(dev, "%s: pairwise key\n", __func__);
+		ether_addr_copy(mac_addr, sta->addr);
+	} else {
+		dev_dbg(dev, "%s: group key\n", __func__);
+		eth_broadcast_addr(mac_addr);
+	}
+
+	val16 = rtl8xxxu_read16(priv, REG_CR);
+	val16 |= CR_SECURITY_ENABLE;
+	rtl8xxxu_write16(priv, REG_CR, val16);
+
+	val8 = SEC_CFG_TX_SEC_ENABLE | SEC_CFG_TXBC_USE_DEFKEY |
+		SEC_CFG_RX_SEC_ENABLE | SEC_CFG_RXBC_USE_DEFKEY;
+	val8 |= SEC_CFG_TX_USE_DEFKEY | SEC_CFG_RX_USE_DEFKEY;
+	rtl8xxxu_write8(priv, REG_SECURITY_CFG, val8);
+
+	switch (cmd) {
+	case SET_KEY:
+		key->hw_key_idx = key->keyidx;
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		rtl8xxxu_cam_write(priv, key, mac_addr);
+		retval = 0;
+		break;
+	case DISABLE_KEY:
+		rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000);
+		val32 = CAM_CMD_POLLING | CAM_CMD_WRITE |
+			key->keyidx << CAM_CMD_KEY_SHIFT;
+		rtl8xxxu_write32(priv, REG_CAM_CMD, val32);
+		retval = 0;
+		break;
+	default:
+		dev_warn(dev, "%s: Unsupported command %02x\n", __func__, cmd);
+	}
+
+	return retval;
+}
+
+static int
+rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+		      enum ieee80211_ampdu_mlme_action action,
+		      struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
+		      bool amsdu)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct device *dev = &priv->udev->dev;
+	u8 ampdu_factor, ampdu_density;
+
+	switch (action) {
+	case IEEE80211_AMPDU_TX_START:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_START\n", __func__);
+		ampdu_factor = sta->ht_cap.ampdu_factor;
+		ampdu_density = sta->ht_cap.ampdu_density;
+		rtl8xxxu_set_ampdu_factor(priv, ampdu_factor);
+		rtl8xxxu_set_ampdu_min_space(priv, ampdu_density);
+		dev_dbg(dev,
+			"Changed HT: ampdu_factor %02x, ampdu_density %02x\n",
+			ampdu_factor, ampdu_density);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);
+		rtl8xxxu_set_ampdu_factor(priv, 0);
+		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		break;
+	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+		dev_info(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",
+			 __func__);
+		rtl8xxxu_set_ampdu_factor(priv, 0);
+		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		break;
+	case IEEE80211_AMPDU_RX_START:
+		dev_info(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);
+		break;
+	case IEEE80211_AMPDU_RX_STOP:
+		dev_info(dev, "%s: IEEE80211_AMPDU_RX_STOP\n", __func__);
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int rtl8xxxu_start(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	struct rtl8xxxu_rx_urb *rx_urb;
+	struct rtl8xxxu_tx_urb *tx_urb;
+	unsigned long flags;
+	int ret, i;
+
+	ret = 0;
+
+	init_usb_anchor(&priv->rx_anchor);
+	init_usb_anchor(&priv->tx_anchor);
+	init_usb_anchor(&priv->int_anchor);
+
+	rtl8723a_enable_rf(priv);
+	ret = rtl8xxxu_submit_int_urb(hw);
+	if (ret)
+		goto exit;
+
+	for (i = 0; i < RTL8XXXU_TX_URBS; i++) {
+		tx_urb = kmalloc(sizeof(struct rtl8xxxu_tx_urb), GFP_KERNEL);
+		if (!tx_urb) {
+			if (!i)
+				ret = -ENOMEM;
+
+			goto error_out;
+		}
+		usb_init_urb(&tx_urb->urb);
+		INIT_LIST_HEAD(&tx_urb->list);
+		tx_urb->hw = hw;
+		list_add(&tx_urb->list, &priv->tx_urb_free_list);
+		priv->tx_urb_free_count++;
+	}
+
+	priv->tx_stopped = false;
+
+	spin_lock_irqsave(&priv->rx_urb_lock, flags);
+	priv->shutdown = false;
+	spin_unlock_irqrestore(&priv->rx_urb_lock, flags);
+
+	for (i = 0; i < RTL8XXXU_RX_URBS; i++) {
+		rx_urb = kmalloc(sizeof(struct rtl8xxxu_rx_urb), GFP_KERNEL);
+		if (!rx_urb) {
+			if (!i)
+				ret = -ENOMEM;
+
+			goto error_out;
+		}
+		usb_init_urb(&rx_urb->urb);
+		INIT_LIST_HEAD(&rx_urb->list);
+		rx_urb->hw = hw;
+
+		ret = rtl8xxxu_submit_rx_urb(priv, rx_urb);
+	}
+exit:
+	/*
+	 * Disable all data frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+	/*
+	 * Accept all mgmt frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0xffff);
+
+	rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, 0x6954341e);
+
+	return ret;
+
+error_out:
+	rtl8xxxu_free_tx_resources(priv);
+	/*
+	 * Disable all data and mgmt frames
+	 */
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000);
+
+	return ret;
+}
+
+static void rtl8xxxu_stop(struct ieee80211_hw *hw)
+{
+	struct rtl8xxxu_priv *priv = hw->priv;
+	unsigned long flags;
+
+	rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
+	rtl8xxxu_write16(priv, REG_RXFLTMAP0, 0x0000);
+	rtl8xxxu_write16(priv, REG_RXFLTMAP2, 0x0000);
+
+	spin_lock_irqsave(&priv->rx_urb_lock, flags);
+	priv->shutdown = true;
+	spin_unlock_irqrestore(&priv->rx_urb_lock, flags);
+
+	usb_kill_anchored_urbs(&priv->rx_anchor);
+	usb_kill_anchored_urbs(&priv->tx_anchor);
+	usb_kill_anchored_urbs(&priv->int_anchor);
+
+	rtl8723a_disable_rf(priv);
+
+	/*
+	 * Disable interrupts
+	 */
+	rtl8xxxu_write32(priv, REG_USB_HIMR, 0);
+
+	rtl8xxxu_free_rx_resources(priv);
+	rtl8xxxu_free_tx_resources(priv);
+}
+
+static const struct ieee80211_ops rtl8xxxu_ops = {
+	.tx = rtl8xxxu_tx,
+	.add_interface = rtl8xxxu_add_interface,
+	.remove_interface = rtl8xxxu_remove_interface,
+	.config = rtl8xxxu_config,
+	.conf_tx = rtl8xxxu_conf_tx,
+	.bss_info_changed = rtl8xxxu_bss_info_changed,
+	.configure_filter = rtl8xxxu_configure_filter,
+	.set_rts_threshold = rtl8xxxu_set_rts_threshold,
+	.start = rtl8xxxu_start,
+	.stop = rtl8xxxu_stop,
+	.sw_scan_start = rtl8xxxu_sw_scan_start,
+	.sw_scan_complete = rtl8xxxu_sw_scan_complete,
+	.set_key = rtl8xxxu_set_key,
+	.ampdu_action = rtl8xxxu_ampdu_action,
+};
+
+static int rtl8xxxu_parse_usb(struct rtl8xxxu_priv *priv,
+			      struct usb_interface *interface)
+{
+	struct usb_interface_descriptor *interface_desc;
+	struct usb_host_interface *host_interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct device *dev = &priv->udev->dev;
+	int i, j = 0, endpoints;
+	u8 dir, xtype, num;
+	int ret = 0;
+
+	host_interface = &interface->altsetting[0];
+	interface_desc = &host_interface->desc;
+	endpoints = interface_desc->bNumEndpoints;
+
+	for (i = 0; i < endpoints; i++) {
+		endpoint = &host_interface->endpoint[i].desc;
+
+		dir = endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		num = usb_endpoint_num(endpoint);
+		xtype = usb_endpoint_type(endpoint);
+		if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+			dev_dbg(dev,
+				"%s: endpoint: dir %02x, # %02x, type %02x\n",
+				__func__, dir, num, xtype);
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: in endpoint num %i\n",
+					__func__, num);
+
+			if (priv->pipe_in) {
+				dev_warn(dev,
+					 "%s: Too many IN pipes\n", __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			priv->pipe_in =	usb_rcvbulkpipe(priv->udev, num);
+		}
+
+		if (usb_endpoint_dir_in(endpoint) &&
+		    usb_endpoint_xfer_int(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: interrupt endpoint num %i\n",
+					__func__, num);
+
+			if (priv->pipe_interrupt) {
+				dev_warn(dev, "%s: Too many INTERRUPT pipes\n",
+					 __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+
+			priv->pipe_interrupt = usb_rcvintpipe(priv->udev, num);
+		}
+
+		if (usb_endpoint_dir_out(endpoint) &&
+		    usb_endpoint_xfer_bulk(endpoint)) {
+			if (rtl8xxxu_debug & RTL8XXXU_DEBUG_USB)
+				dev_dbg(dev, "%s: out endpoint num %i\n",
+					__func__, num);
+			if (j >= RTL8XXXU_OUT_ENDPOINTS) {
+				dev_warn(dev,
+					 "%s: Too many OUT pipes\n", __func__);
+				ret = -EINVAL;
+				goto exit;
+			}
+			priv->out_ep[j++] = num;
+		}
+	}
+exit:
+	priv->nr_out_eps = j;
+	return ret;
+}
+
+static int rtl8xxxu_probe(struct usb_interface *interface,
+			  const struct usb_device_id *id)
+{
+	struct rtl8xxxu_priv *priv;
+	struct ieee80211_hw *hw;
+	struct usb_device *udev;
+	struct ieee80211_supported_band *sband;
+	int ret = 0;
+	int untested = 1;
+
+	udev = usb_get_dev(interface_to_usbdev(interface));
+
+	switch (id->idVendor) {
+	case USB_VENDOR_ID_REALTEK:
+		switch(id->idProduct) {
+		case 0x1724:
+		case 0x8176:
+		case 0x8178:
+		case 0x817f:
+			untested = 0;
+			break;
+		}
+		break;
+	case 0x7392:
+		if (id->idProduct == 0x7811)
+			untested = 0;
+		break;
+	default:
+		break;
+	}
+
+	if (untested) {
+		rtl8xxxu_debug = RTL8XXXU_DEBUG_EFUSE;
+		dev_info(&udev->dev,
+			 "This Realtek USB WiFi dongle (0x%04x:0x%04x) is untested!\n",
+			 id->idVendor, id->idProduct);
+		dev_info(&udev->dev,
+			 "Please report results to Jes.Sorensen@gmail.com\n");
+	}
+
+	hw = ieee80211_alloc_hw(sizeof(struct rtl8xxxu_priv), &rtl8xxxu_ops);
+	if (!hw) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	priv = hw->priv;
+	priv->hw = hw;
+	priv->udev = udev;
+	priv->fops = (struct rtl8xxxu_fileops *)id->driver_info;
+	mutex_init(&priv->usb_buf_mutex);
+	mutex_init(&priv->h2c_mutex);
+	INIT_LIST_HEAD(&priv->tx_urb_free_list);
+	spin_lock_init(&priv->tx_urb_lock);
+	INIT_LIST_HEAD(&priv->rx_urb_pending_list);
+	spin_lock_init(&priv->rx_urb_lock);
+	INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work);
+
+	usb_set_intfdata(interface, hw);
+
+	ret = rtl8xxxu_parse_usb(priv, interface);
+	if (ret)
+		goto exit;
+
+	ret = rtl8xxxu_identify_chip(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to identify chip\n");
+		goto exit;
+	}
+
+	ret = rtl8xxxu_read_efuse(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to read EFuse\n");
+		goto exit;
+	}
+
+	ret = priv->fops->parse_efuse(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to parse EFuse\n");
+		goto exit;
+	}
+
+	rtl8xxxu_print_chipinfo(priv);
+
+	ret = priv->fops->load_firmware(priv);
+	if (ret) {
+		dev_err(&udev->dev, "Fatal - failed to load firmware\n");
+		goto exit;
+	}
+
+	ret = rtl8xxxu_init_device(hw);
+
+	hw->wiphy->max_scan_ssids = 1;
+	hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+	hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+	hw->queues = 4;
+
+	sband = &rtl8xxxu_supported_band;
+	sband->ht_cap.ht_supported = true;
+	sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+	sband->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+	sband->ht_cap.cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40;
+	memset(&sband->ht_cap.mcs, 0, sizeof(sband->ht_cap.mcs));
+	sband->ht_cap.mcs.rx_mask[0] = 0xff;
+	sband->ht_cap.mcs.rx_mask[4] = 0x01;
+	if (priv->rf_paths > 1) {
+		sband->ht_cap.mcs.rx_mask[1] = 0xff;
+		sband->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+	}
+	sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+	/*
+	 * Some APs will negotiate HT20_40 in a noisy environment leading
+	 * to miserable performance. Rather than defaulting to this, only
+	 * enable it if explicitly requested at module load time.
+	 */
+	if (rtl8xxxu_ht40_2g) {
+		dev_info(&udev->dev, "Enabling HT_20_40 on the 2.4GHz band\n");
+		sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+	}
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+
+	hw->wiphy->rts_threshold = 2347;
+
+	SET_IEEE80211_DEV(priv->hw, &interface->dev);
+	SET_IEEE80211_PERM_ADDR(hw, priv->mac_addr);
+
+	hw->extra_tx_headroom = sizeof(struct rtl8xxxu_tx_desc);
+	ieee80211_hw_set(hw, SIGNAL_DBM);
+	/*
+	 * The firmware handles rate control
+	 */
+	ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+	ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
+	ret = ieee80211_register_hw(priv->hw);
+	if (ret) {
+		dev_err(&udev->dev, "%s: Failed to register: %i\n",
+			__func__, ret);
+		goto exit;
+	}
+
+exit:
+	if (ret < 0)
+		usb_put_dev(udev);
+	return ret;
+}
+
+static void rtl8xxxu_disconnect(struct usb_interface *interface)
+{
+	struct rtl8xxxu_priv *priv;
+	struct ieee80211_hw *hw;
+
+	hw = usb_get_intfdata(interface);
+	priv = hw->priv;
+
+	rtl8xxxu_disable_device(hw);
+	usb_set_intfdata(interface, NULL);
+
+	dev_info(&priv->udev->dev, "disconnecting\n");
+
+	ieee80211_unregister_hw(hw);
+
+	kfree(priv->fw_data);
+	mutex_destroy(&priv->usb_buf_mutex);
+	mutex_destroy(&priv->h2c_mutex);
+
+	usb_put_dev(priv->udev);
+	ieee80211_free_hw(hw);
+}
+
+static struct rtl8xxxu_fileops rtl8723au_fops = {
+	.parse_efuse = rtl8723au_parse_efuse,
+	.load_firmware = rtl8723au_load_firmware,
+	.power_on = rtl8723au_power_on,
+	.writeN_block_size = 1024,
+};
+
+static struct rtl8xxxu_fileops rtl8192cu_fops = {
+	.parse_efuse = rtl8192cu_parse_efuse,
+	.load_firmware = rtl8192cu_load_firmware,
+	.power_on = rtl8192cu_power_on,
+	.writeN_block_size = 128,
+};
+
+static struct usb_device_id dev_table[] = {
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x0724, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8723au_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8178, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+/* Tested by Larry Finger */
+{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7811, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+#ifdef CONFIG_RTL8XXXU_UNTESTED
+/* Currently untested 8188 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8170, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8177, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x817e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x818a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x1058, 0x0631, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x094c, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1102, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ba, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x1e1e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x5088, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0052, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x005c, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0eb0, 0x9071, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x103c, 0x1629, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x13d3, 0x3357, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3308, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x4902, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xed17, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x648b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0090, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4856, 0x0091, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0xcdab, 0x8010, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops}, /* Netcore 8188RU */
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff7, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff9, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffa, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaff8, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffb, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x04f2, 0xaffc, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0x1201, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+/* Currently untested 8192 series devices */
+{USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0950, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2102, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2103, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x341f, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe035, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x17ab, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0061, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0df6, 0x0070, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0789, 0x016d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07aa, 0x0056, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8178, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9021, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0xf001, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x2e2e, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0019, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x0e66, 0x0020, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3307, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x3309, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x330a, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2019, 0xab2b, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x20f4, 0x624d, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x2357, 0x0100, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x4855, 0x0091, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7822, 0xff, 0xff, 0xff),
+	.driver_info = (unsigned long)&rtl8192cu_fops},
+#endif
+{ }
+};
+
+static struct usb_driver rtl8xxxu_driver = {
+	.name = DRIVER_NAME,
+	.probe = rtl8xxxu_probe,
+	.disconnect = rtl8xxxu_disconnect,
+	.id_table = dev_table,
+	.disable_hub_initiated_lpm = 1,
+};
+
+static int __init rtl8xxxu_module_init(void)
+{
+	int res;
+
+	res = usb_register(&rtl8xxxu_driver);
+	if (res < 0)
+		pr_err(DRIVER_NAME ": usb_register() failed (%i)\n", res);
+
+	return res;
+}
+
+static void __exit rtl8xxxu_module_exit(void)
+{
+	usb_deregister(&rtl8xxxu_driver);
+}
+
+
+MODULE_DEVICE_TABLE(usb, dev_table);
+
+module_init(rtl8xxxu_module_init);
+module_exit(rtl8xxxu_module_exit);
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
new file mode 100644
index 0000000..f2a1bac
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Register definitions taken from original Realtek rtl8723au driver
+ */
+
+#include <asm/byteorder.h>
+
+#define RTL8XXXU_DEBUG_REG_WRITE	0x01
+#define RTL8XXXU_DEBUG_REG_READ		0x02
+#define RTL8XXXU_DEBUG_RFREG_WRITE	0x04
+#define RTL8XXXU_DEBUG_RFREG_READ	0x08
+#define RTL8XXXU_DEBUG_CHANNEL		0x10
+#define RTL8XXXU_DEBUG_TX		0x20
+#define RTL8XXXU_DEBUG_TX_DUMP		0x40
+#define RTL8XXXU_DEBUG_RX		0x80
+#define RTL8XXXU_DEBUG_RX_DUMP		0x100
+#define RTL8XXXU_DEBUG_USB		0x200
+#define RTL8XXXU_DEBUG_KEY		0x400
+#define RTL8XXXU_DEBUG_H2C		0x800
+#define RTL8XXXU_DEBUG_ACTION		0x1000
+#define RTL8XXXU_DEBUG_EFUSE		0x2000
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT	500
+#define RTL8XXXU_MAX_REG_POLL		500
+#define	USB_INTR_CONTENT_LENGTH		56
+
+#define RTL8XXXU_OUT_ENDPOINTS		3
+
+#define REALTEK_USB_READ		0xc0
+#define REALTEK_USB_WRITE		0x40
+#define REALTEK_USB_CMD_REQ		0x05
+#define REALTEK_USB_CMD_IDX		0x00
+
+#define TX_TOTAL_PAGE_NUM		0xf8
+/* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */
+#define TX_PAGE_NUM_PUBQ		0xe7
+#define TX_PAGE_NUM_HI_PQ		0x0c
+#define TX_PAGE_NUM_LO_PQ		0x02
+#define TX_PAGE_NUM_NORM_PQ		0x02
+
+#define RTL_FW_PAGE_SIZE		4096
+#define RTL8XXXU_FIRMWARE_POLL_MAX	1000
+
+#define RTL8723A_CHANNEL_GROUPS		3
+#define RTL8723A_MAX_RF_PATHS		2
+#define RF6052_MAX_TX_PWR		0x3f
+
+#define EFUSE_MAP_LEN_8723A		256
+#define EFUSE_MAX_SECTION_8723A		32
+#define EFUSE_REAL_CONTENT_LEN_8723A	512
+#define EFUSE_BT_MAP_LEN_8723A		1024
+#define EFUSE_MAX_WORD_UNIT		4
+
+struct rtl8xxxu_rx_desc {
+#ifdef __LITTLE_ENDIAN
+	u32 pktlen:14;
+	u32 crc32:1;
+	u32 icverr:1;
+	u32 drvinfo_sz:4;
+	u32 security:3;
+	u32 qos:1;
+	u32 shift:2;
+	u32 phy_stats:1;
+	u32 swdec:1;
+	u32 ls:1;
+	u32 fs:1;
+	u32 eor:1;
+	u32 own:1;
+
+	u32 macid:5;
+	u32 tid:4;
+	u32 hwrsvd:4;
+	u32 amsdu:1;
+	u32 paggr:1;
+	u32 faggr:1;
+	u32 a1fit:4;
+	u32 a2fit:4;
+	u32 pam:1;
+	u32 pwr:1;
+	u32 md:1;
+	u32 mf:1;
+	u32 type:2;
+	u32 mc:1;
+	u32 bc:1;
+
+	u32 seq:12;
+	u32 frag:4;
+	u32 nextpktlen:14;
+	u32 nextind:1;
+	u32 reserved0:1;
+
+	u32 rxmcs:6;
+	u32 rxht:1;
+	u32 gf:1;
+	u32 splcp:1;
+	u32 bw:1;
+	u32 htc:1;
+	u32 eosp:1;
+	u32 bssidfit:2;
+	u32 reserved1:16;
+	u32 unicastwake:1;
+	u32 magicwake:1;
+
+	u32 pattern0match:1;
+	u32 pattern1match:1;
+	u32 pattern2match:1;
+	u32 pattern3match:1;
+	u32 pattern4match:1;
+	u32 pattern5match:1;
+	u32 pattern6match:1;
+	u32 pattern7match:1;
+	u32 pattern8match:1;
+	u32 pattern9match:1;
+	u32 patternamatch:1;
+	u32 patternbmatch:1;
+	u32 patterncmatch:1;
+	u32 reserved2:19;
+#else
+	u32 own:1;
+	u32 eor:1;
+	u32 fs:1;
+	u32 ls:1;
+	u32 swdec:1;
+	u32 phy_stats:1;
+	u32 shift:2;
+	u32 qos:1;
+	u32 security:3;
+	u32 drvinfo_sz:4;
+	u32 icverr:1;
+	u32 crc32:1;
+	u32 pktlen:14;
+
+	u32 bc:1;
+	u32 mc:1;
+	u32 type:2;
+	u32 mf:1;
+	u32 md:1;
+	u32 pwr:1;
+	u32 pam:1;
+	u32 a2fit:4;
+	u32 a1fit:4;
+	u32 faggr:1;
+	u32 paggr:1;
+	u32 amsdu:1;
+	u32 hwrsvd:4;
+	u32 tid:4;
+	u32 macid:5;
+
+	u32 reserved0:1;
+	u32 nextind:1;
+	u32 nextpktlen:14;
+	u32 frag:4;
+	u32 seq:12;
+
+	u32 magicwake:1;
+	u32 unicastwake:1;
+	u32 reserved1:16;
+	u32 bssidfit:2;
+	u32 eosp:1;
+	u32 htc:1;
+	u32 bw:1;
+	u32 splcp:1;
+	u32 gf:1;
+	u32 rxht:1;
+	u32 rxmcs:6;
+
+	u32 reserved2:19;
+	u32 patterncmatch:1;
+	u32 patternbmatch:1;
+	u32 patternamatch:1;
+	u32 pattern9match:1;
+	u32 pattern8match:1;
+	u32 pattern7match:1;
+	u32 pattern6match:1;
+	u32 pattern5match:1;
+	u32 pattern4match:1;
+	u32 pattern3match:1;
+	u32 pattern2match:1;
+	u32 pattern1match:1;
+	u32 pattern0match:1;
+#endif
+	__le32 tsfl;
+#if 0
+	u32 bassn:12;
+	u32 bavld:1;
+	u32 reserved3:19;
+#endif
+};
+
+struct rtl8xxxu_tx_desc {
+	__le16 pkt_size;
+	u8 pkt_offset;
+	u8 txdw0;
+	__le32 txdw1;
+	__le32 txdw2;
+	__le32 txdw3;
+	__le32 txdw4;
+	__le32 txdw5;
+	__le32 txdw6;
+	__le16 csum;
+	__le16 txdw7;
+};
+
+/*  CCK Rates, TxHT = 0 */
+#define DESC_RATE_1M			0x00
+#define DESC_RATE_2M			0x01
+#define DESC_RATE_5_5M			0x02
+#define DESC_RATE_11M			0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC_RATE_6M			0x04
+#define DESC_RATE_9M			0x05
+#define DESC_RATE_12M			0x06
+#define DESC_RATE_18M			0x07
+#define DESC_RATE_24M			0x08
+#define DESC_RATE_36M			0x09
+#define DESC_RATE_48M			0x0a
+#define DESC_RATE_54M			0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC_RATE_MCS0			0x0c
+#define DESC_RATE_MCS1			0x0d
+#define DESC_RATE_MCS2			0x0e
+#define DESC_RATE_MCS3			0x0f
+#define DESC_RATE_MCS4			0x10
+#define DESC_RATE_MCS5			0x11
+#define DESC_RATE_MCS6			0x12
+#define DESC_RATE_MCS7			0x13
+#define DESC_RATE_MCS8			0x14
+#define DESC_RATE_MCS9			0x15
+#define DESC_RATE_MCS10			0x16
+#define DESC_RATE_MCS11			0x17
+#define DESC_RATE_MCS12			0x18
+#define DESC_RATE_MCS13			0x19
+#define DESC_RATE_MCS14			0x1a
+#define DESC_RATE_MCS15			0x1b
+#define DESC_RATE_MCS15_SG		0x1c
+#define DESC_RATE_MCS32			0x20
+
+#define TXDESC_OFFSET_SZ		0
+#define TXDESC_OFFSET_SHT		16
+#if 0
+#define TXDESC_BMC			BIT(24)
+#define TXDESC_LSG			BIT(26)
+#define TXDESC_FSG			BIT(27)
+#define TXDESC_OWN			BIT(31)
+#else
+#define TXDESC_BROADMULTICAST		BIT(0)
+#define TXDESC_LAST_SEGMENT		BIT(2)
+#define TXDESC_FIRST_SEGMENT		BIT(3)
+#define TXDESC_OWN			BIT(7)
+#endif
+
+/* Word 1 */
+#define TXDESC_PKT_OFFSET_SZ		0
+#define TXDESC_AGG_ENABLE		BIT(5)
+#define TXDESC_BK			BIT(6)
+#define TXDESC_QUEUE_SHIFT		8
+#define TXDESC_QUEUE_MASK		0x1f00
+#define TXDESC_QUEUE_BK			0x2
+#define TXDESC_QUEUE_BE			0x0
+#define TXDESC_QUEUE_VI			0x5
+#define TXDESC_QUEUE_VO			0x7
+#define TXDESC_QUEUE_BEACON		0x10
+#define TXDESC_QUEUE_HIGH		0x11
+#define TXDESC_QUEUE_MGNT		0x12
+#define TXDESC_QUEUE_CMD		0x13
+#define TXDESC_QUEUE_MAX		(TXDESC_QUEUE_CMD + 1)
+
+#define DESC_RATE_ID_SHIFT		16
+#define DESC_RATE_ID_MASK		0xf
+#define TXDESC_NAVUSEHDR		BIT(20)
+#define TXDESC_SEC_RC4			0x00400000
+#define TXDESC_SEC_AES			0x00c00000
+#define TXDESC_PKT_OFFSET_SHIFT		26
+#define TXDESC_AGG_EN			BIT(29)
+#define TXDESC_HWPC			BIT(31)
+
+/* Word 2 */
+#define TXDESC_ACK_REPORT		BIT(19)
+#define TXDESC_AMPDU_DENSITY_SHIFT	20
+
+/* Word 3 */
+#define TXDESC_SEQ_SHIFT		16
+#define TXDESC_SEQ_MASK			0x0fff0000
+
+/* Word 4 */
+#define TXDESC_QOS			BIT(6)
+#define TXDESC_HW_SEQ_ENABLE		BIT(7)
+#define TXDESC_USE_DRIVER_RATE		BIT(8)
+#define TXDESC_DISABLE_DATA_FB		BIT(10)
+#define TXDESC_CTS_SELF_ENABLE		BIT(11)
+#define TXDESC_RTS_CTS_ENABLE		BIT(12)
+#define TXDESC_HW_RTS_ENABLE		BIT(13)
+#define TXDESC_PRIME_CH_OFF_LOWER	BIT(20)
+#define TXDESC_PRIME_CH_OFF_UPPER	BIT(21)
+#define TXDESC_SHORT_PREAMBLE		BIT(24)
+#define TXDESC_DATA_BW			BIT(25)
+#define TXDESC_RTS_DATA_BW		BIT(27)
+#define TXDESC_RTS_PRIME_CH_OFF_LOWER	BIT(28)
+#define TXDESC_RTS_PRIME_CH_OFF_UPPER	BIT(29)
+
+/* Word 5 */
+#define TXDESC_RTS_RATE_SHIFT		0
+#define TXDESC_RTS_RATE_MASK		0x3f
+#define TXDESC_SHORT_GI			BIT(6)
+#define TXDESC_CCX_TAG			BIT(7)
+#define TXDESC_RETRY_LIMIT_ENABLE	BIT(17)
+#define TXDESC_RETRY_LIMIT_SHIFT	18
+#define TXDESC_RETRY_LIMIT_MASK		0x00fc0000
+
+/* Word 6 */
+#define TXDESC_MAX_AGG_SHIFT		11
+
+struct phy_rx_agc_info {
+#ifdef __LITTLE_ENDIAN
+	u8	gain:7, trsw:1;
+#else
+	u8	trsw:1, gain:7;
+#endif
+};
+
+struct rtl8723au_phy_stats {
+	struct phy_rx_agc_info path_agc[RTL8723A_MAX_RF_PATHS];
+	u8	ch_corr[RTL8723A_MAX_RF_PATHS];
+	u8	cck_sig_qual_ofdm_pwdb_all;
+	u8	cck_agc_rpt_ofdm_cfosho_a;
+	u8	cck_rpt_b_ofdm_cfosho_b;
+	u8	reserved_1;
+	u8	noise_power_db_msb;
+	u8	path_cfotail[RTL8723A_MAX_RF_PATHS];
+	u8	pcts_mask[RTL8723A_MAX_RF_PATHS];
+	s8	stream_rxevm[RTL8723A_MAX_RF_PATHS];
+	u8	path_rxsnr[RTL8723A_MAX_RF_PATHS];
+	u8	noise_power_db_lsb;
+	u8	reserved_2[3];
+	u8	stream_csi[RTL8723A_MAX_RF_PATHS];
+	u8	stream_target_csi[RTL8723A_MAX_RF_PATHS];
+	s8	sig_evm;
+	u8	reserved_3;
+
+#ifdef __LITTLE_ENDIAN
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+	u8	sgi_en:1;
+	u8	rxsc:2;
+	u8	idle_long:1;
+	u8	r_ant_train_en:1;
+	u8	antenna_select_b:1;
+	u8	antenna_select:1;
+#else	/*  _BIG_ENDIAN_ */
+	u8	antenna_select:1;
+	u8	antenna_select_b:1;
+	u8	r_ant_train_en:1;
+	u8	idle_long:1;
+	u8	rxsc:2;
+	u8	sgi_en:1;
+	u8	antsel_rx_keep_2:1;	/* ex_intf_flg:1; */
+#endif
+};
+
+/*
+ * Regs to backup
+ */
+#define RTL8XXXU_ADDA_REGS		16
+#define RTL8XXXU_MAC_REGS		4
+#define RTL8XXXU_BB_REGS		9
+
+struct rtl8xxxu_firmware_header {
+	__le16	signature;		/*  92C0: test chip; 92C,
+					    88C0: test chip;
+					    88C1: MP A-cut;
+					    92C1: MP A-cut */
+	u8	category;		/*  AP/NIC and USB/PCI */
+	u8	function;
+
+	__le16	major_version;		/*  FW Version */
+	u8	minor_version;		/*  FW Subversion, default 0x00 */
+	u8	reserved1;
+
+	u8	month;			/*  Release time Month field */
+	u8	date;			/*  Release time Date field */
+	u8	hour;			/*  Release time Hour field */
+	u8	minute;			/*  Release time Minute field */
+
+	__le16	ramcodesize;		/*  Size of RAM code */
+	u16	reserved2;
+
+	__le32	svn_idx;		/*  SVN entry index */
+	u32	reserved3;
+
+	u32	reserved4;
+	u32	reserved5;
+
+	u8	data[0];
+};
+
+/*
+ * The 8723au has 3 channel groups: 1-3, 4-9, and 10-14
+ */
+struct rtl8723au_idx {
+#ifdef __LITTLE_ENDIAN
+	int	a:4;
+	int	b:4;
+#else
+	int	b:4;
+	int	a:4;
+#endif
+} __attribute__((packed));
+
+struct rtl8723au_efuse {
+	__le16 rtl_id;
+	u8 res0[0xe];
+	u8 cck_tx_power_index_A[3];	/* 0x10 */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
+	u8 ht40_1s_tx_power_index_B[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u8 channel_plan;		/* 0x28 */
+	u8 tssi_a;
+	u8 thermal_meter;
+	u8 rf_regulatory;
+	u8 rf_option_2;
+	u8 rf_option_3;
+	u8 rf_option_4;
+	u8 res7;
+	u8 version			/* 0x30 */;
+	u8 customer_id_major;
+	u8 customer_id_minor;
+	u8 xtal_k;
+	u8 chipset;			/* 0x34 */
+	u8 res8[0x82];
+	u8 vid;				/* 0xb7 */
+	u8 res9;
+	u8 pid;				/* 0xb9 */
+	u8 res10[0x0c];
+	u8 mac_addr[ETH_ALEN];		/* 0xc6 */
+	u8 res11[2];
+	u8 vendor_name[7];
+	u8 res12[2];
+	u8 device_name[0x29];		/* 0xd7 */
+};
+
+struct rtl8192cu_efuse {
+	__le16 rtl_id;
+	__le16 hpon;
+	u8 res0[2];
+	__le16 clk;
+	__le16 testr;
+	__le16 vid;
+	__le16 did;
+	__le16 svid;
+	__le16 smid;						/* 0x10 */
+	u8 res1[4];
+	u8 mac_addr[ETH_ALEN];					/* 0x16 */
+	u8 res2[2];
+	u8 vendor_name[7];
+	u8 res3[3];
+	u8 device_name[0x14];					/* 0x28 */
+	u8 res4[0x1e];						/* 0x3c */
+	u8 cck_tx_power_index_A[3];				/* 0x5a */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];				/* 0x60 */
+	u8 ht40_1s_tx_power_index_B[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht40_2s_tx_power_index_diff[3];
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];	/* 0x69 */
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];		/* 0x6f */
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u8 channel_plan;					/* 0x75 */
+	u8 tssi_a;
+	u8 tssi_b;
+	u8 thermal_meter;	/* xtal_k */			/* 0x78 */
+	u8 rf_regulatory;
+	u8 rf_option_2;
+	u8 rf_option_3;
+	u8 rf_option_4;
+	u8 res5[1];						/* 0x7d */
+	u8 version;
+	u8 customer_id;
+};
+
+struct rtl8xxxu_reg8val {
+	u16 reg;
+	u8 val;
+};
+
+struct rtl8xxxu_reg32val {
+	u16 reg;
+	u32 val;
+};
+
+struct rtl8xxxu_rfregval {
+	u8 reg;
+	u32 val;
+};
+
+enum rtl8xxxu_rfpath {
+	RF_A = 0,
+	RF_B = 1,
+};
+
+struct rtl8xxxu_rfregs {
+	u16 hssiparm1;
+	u16 hssiparm2;
+	u16 lssiparm;
+	u16 hspiread;
+	u16 lssiread;
+	u16 rf_sw_ctrl;
+};
+
+#define H2C_MAX_MBOX			4
+#define H2C_EXT				BIT(7)
+#define H2C_SET_POWER_MODE		1
+#define H2C_JOIN_BSS_REPORT		2
+#define  H2C_JOIN_BSS_DISCONNECT	0
+#define  H2C_JOIN_BSS_CONNECT		1
+#define H2C_SET_RSSI			5
+#define H2C_SET_RATE_MASK		(6 | H2C_EXT)
+
+struct h2c_cmd {
+	union {
+		struct {
+			u8 cmd;
+			u8 data[5];
+		} __packed cmd;
+		struct {
+			__le32 data;
+			__le16 ext;
+		} __packed raw;
+		struct {
+			u8 cmd;
+			u8 data;
+			u8 pad[4];
+		} __packed joinbss;
+		struct {
+			u8 cmd;
+			__le16 mask_hi;
+			u8 arg;
+			__le16 mask_lo;
+		} __packed ramask;
+	};
+};
+
+struct rtl8xxxu_fileops;
+
+struct rtl8xxxu_priv {
+	struct ieee80211_hw *hw;
+	struct usb_device *udev;
+	struct rtl8xxxu_fileops *fops;
+
+	spinlock_t tx_urb_lock;
+	struct list_head tx_urb_free_list;
+	int tx_urb_free_count;
+	bool tx_stopped;
+
+	spinlock_t rx_urb_lock;
+	struct list_head rx_urb_pending_list;
+	int rx_urb_pending_count;
+	bool shutdown;
+	struct work_struct rx_urb_wq;
+
+	u8 mac_addr[ETH_ALEN];
+	char chip_name[8];
+	u8 cck_tx_power_index_A[3];	/* 0x10 */
+	u8 cck_tx_power_index_B[3];
+	u8 ht40_1s_tx_power_index_A[3];	/* 0x16 */
+	u8 ht40_1s_tx_power_index_B[3];
+	/*
+	 * The following entries are half-bytes split as:
+	 * bits 0-3: path A, bits 4-7: path B, all values 4 bits signed
+	 */
+	struct rtl8723au_idx ht40_2s_tx_power_index_diff[3];
+	struct rtl8723au_idx ht20_tx_power_index_diff[3];
+	struct rtl8723au_idx ofdm_tx_power_index_diff[3];
+	struct rtl8723au_idx ht40_max_power_offset[3];
+	struct rtl8723au_idx ht20_max_power_offset[3];
+	u32 chip_cut:4;
+	u32 rom_rev:4;
+	u32 has_wifi:1;
+	u32 has_bluetooth:1;
+	u32 enable_bluetooth:1;
+	u32 has_gps:1;
+	u32 hi_pa:1;
+	u32 vendor_umc:1;
+	u32 has_polarity_ctrl:1;
+	u32 has_eeprom:1;
+	u32 boot_eeprom:1;
+	u32 ep_tx_high_queue:1;
+	u32 ep_tx_normal_queue:1;
+	u32 ep_tx_low_queue:1;
+	u32 path_a_hi_power:1;
+	u32 path_a_rf_paths:4;
+	unsigned int pipe_interrupt;
+	unsigned int pipe_in;
+	unsigned int pipe_out[TXDESC_QUEUE_MAX];
+	u8 out_ep[RTL8XXXU_OUT_ENDPOINTS];
+	u8 path_a_ig_value;
+	u8 ep_tx_count;
+	u8 rf_paths;
+	u8 rx_paths;
+	u8 tx_paths;
+	u32 rf_mode_ag[2];
+	u32 rege94;
+	u32 rege9c;
+	u32 regeb4;
+	u32 regebc;
+	int next_mbox;
+	int nr_out_eps;
+
+	struct mutex h2c_mutex;
+
+	struct usb_anchor rx_anchor;
+	struct usb_anchor tx_anchor;
+	struct usb_anchor int_anchor;
+	struct rtl8xxxu_firmware_header *fw_data;
+	size_t fw_size;
+	struct mutex usb_buf_mutex;
+	union {
+		__le32 val32;
+		__le16 val16;
+		u8 val8;
+	} usb_buf;
+	union {
+		u8 raw[EFUSE_MAP_LEN_8723A];
+		struct rtl8723au_efuse efuse8723;
+		struct rtl8192cu_efuse efuse8192;
+	} efuse_wifi;
+	u32 adda_backup[RTL8XXXU_ADDA_REGS];
+	u32 mac_backup[RTL8XXXU_MAC_REGS];
+	u32 bb_backup[RTL8XXXU_BB_REGS];
+	u32 bb_recovery_backup[RTL8XXXU_BB_REGS];
+	u32 rtlchip;
+	u8 pi_enabled:1;
+	u8 iqk_initialized:1;
+	u8 int_buf[USB_INTR_CONTENT_LENGTH];
+};
+
+struct rtl8xxxu_rx_urb {
+	struct urb urb;
+	struct ieee80211_hw *hw;
+	struct list_head list;
+};
+
+struct rtl8xxxu_tx_urb {
+	struct urb urb;
+	struct ieee80211_hw *hw;
+	struct list_head list;
+};
+
+struct rtl8xxxu_fileops {
+	int (*parse_efuse) (struct rtl8xxxu_priv *priv);
+	int (*load_firmware) (struct rtl8xxxu_priv *priv);
+	int (*power_on) (struct rtl8xxxu_priv *priv);
+	int writeN_block_size;
+};
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h
new file mode 100644
index 0000000..23208f7
--- /dev/null
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h
@@ -0,0 +1,981 @@
+/*
+ * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Register definitions taken from original Realtek rtl8723au driver
+ */
+
+/* 0x0000 ~ 0x00FF	System Configuration */
+#define REG_SYS_ISO_CTRL		0x0000
+#define  SYS_ISO_MD2PP			BIT(0)
+#define  SYS_ISO_ANALOG_IPS		BIT(5)
+#define  SYS_ISO_DIOR			BIT(9)
+#define  SYS_ISO_PWC_EV25V		BIT(14)
+#define  SYS_ISO_PWC_EV12V		BIT(15)
+
+#define REG_SYS_FUNC			0x0002
+#define  SYS_FUNC_BBRSTB		BIT(0)
+#define  SYS_FUNC_BB_GLB_RSTN		BIT(1)
+#define  SYS_FUNC_USBA			BIT(2)
+#define  SYS_FUNC_UPLL			BIT(3)
+#define  SYS_FUNC_USBD			BIT(4)
+#define  SYS_FUNC_DIO_PCIE		BIT(5)
+#define  SYS_FUNC_PCIEA			BIT(6)
+#define  SYS_FUNC_PPLL			BIT(7)
+#define  SYS_FUNC_PCIED			BIT(8)
+#define  SYS_FUNC_DIOE			BIT(9)
+#define  SYS_FUNC_CPU_ENABLE		BIT(10)
+#define  SYS_FUNC_DCORE			BIT(11)
+#define  SYS_FUNC_ELDR			BIT(12)
+#define  SYS_FUNC_DIO_RF		BIT(13)
+#define  SYS_FUNC_HWPDN			BIT(14)
+#define  SYS_FUNC_MREGEN		BIT(15)
+
+#define REG_APS_FSMCO			0x0004
+#define  APS_FSMCO_PFM_ALDN		BIT(1)
+#define  APS_FSMCO_PFM_WOWL		BIT(3)
+#define  APS_FSMCO_ENABLE_POWERDOWN	BIT(4)
+#define  APS_FSMCO_MAC_ENABLE		BIT(8)
+#define  APS_FSMCO_MAC_OFF		BIT(9)
+#define  APS_FSMCO_HW_SUSPEND		BIT(11)
+#define  APS_FSMCO_PCIE			BIT(12)
+#define  APS_FSMCO_HW_POWERDOWN		BIT(15)
+#define  APS_FSMCO_WLON_RESET		BIT(16)
+
+#define REG_SYS_CLKR			0x0008
+#define  SYS_CLK_ANAD16V_ENABLE		BIT(0)
+#define  SYS_CLK_ANA8M			BIT(1)
+#define  SYS_CLK_MACSLP			BIT(4)
+#define  SYS_CLK_LOADER_ENABLE		BIT(5)
+#define  SYS_CLK_80M_SSC_DISABLE	BIT(7)
+#define  SYS_CLK_80M_SSC_ENABLE_HO	BIT(8)
+#define  SYS_CLK_PHY_SSC_RSTB		BIT(9)
+#define  SYS_CLK_SEC_CLK_ENABLE		BIT(10)
+#define  SYS_CLK_MAC_CLK_ENABLE		BIT(11)
+#define  SYS_CLK_ENABLE			BIT(12)
+#define  SYS_CLK_RING_CLK_ENABLE	BIT(13)
+
+#define REG_9346CR			0x000a
+#define  EEPROM_BOOT			BIT(4)
+#define  EEPROM_ENABLE			BIT(5)
+
+#define REG_EE_VPD			0x000c
+#define REG_AFE_MISC			0x0010
+#define REG_SPS0_CTRL			0x0011
+#define REG_SPS_OCP_CFG			0x0018
+#define REG_RSV_CTRL			0x001c
+
+#define REG_RF_CTRL			0x001f
+#define  RF_ENABLE			BIT(0)
+#define  RF_RSTB			BIT(1)
+#define  RF_SDMRSTB			BIT(2)
+
+#define REG_LDOA15_CTRL			0x0020
+#define  LDOA15_ENABLE			BIT(0)
+#define  LDOA15_STANDBY			BIT(1)
+#define  LDOA15_OBUF			BIT(2)
+#define  LDOA15_REG_VOS			BIT(3)
+#define  LDOA15_VOADJ_SHIFT		4
+
+#define REG_LDOV12D_CTRL		0x0021
+#define  LDOV12D_ENABLE			BIT(0)
+#define  LDOV12D_STANDBY		BIT(1)
+#define  LDOV12D_VADJ_SHIFT		4
+
+#define REG_LDOHCI12_CTRL		0x0022
+
+#define REG_LPLDO_CTRL			0x0023
+#define  LPLDO_HSM			BIT(2)
+#define  LPLDO_LSM_DIS			BIT(3)
+
+#define REG_AFE_XTAL_CTRL		0x0024
+#define  AFE_XTAL_ENABLE		BIT(0)
+#define  AFE_XTAL_B_SELECT		BIT(1)
+#define  AFE_XTAL_GATE_USB		BIT(8)
+#define  AFE_XTAL_GATE_AFE		BIT(11)
+#define  AFE_XTAL_RF_GATE		BIT(14)
+#define  AFE_XTAL_GATE_DIG		BIT(17)
+#define  AFE_XTAL_BT_GATE		BIT(20)
+
+#define REG_AFE_PLL_CTRL		0x0028
+#define  AFE_PLL_ENABLE			BIT(0)
+#define  AFE_PLL_320_ENABLE		BIT(1)
+#define  APE_PLL_FREF_SELECT		BIT(2)
+#define  AFE_PLL_EDGE_SELECT		BIT(3)
+#define  AFE_PLL_WDOGB			BIT(4)
+#define  AFE_PLL_LPF_ENABLE		BIT(5)
+
+#define REG_MAC_PHY_CTRL		0x002c
+
+#define REG_EFUSE_CTRL			0x0030
+#define REG_EFUSE_TEST			0x0034
+#define  EFUSE_TRPT			BIT(7)
+	/*  00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
+#define  EFUSE_CELL_SEL			(BIT(8) | BIT(9))
+#define  EFUSE_LDOE25_ENABLE		BIT(31)
+#define  EFUSE_SELECT_MASK		0x0300
+#define  EFUSE_WIFI_SELECT		0x0000
+#define  EFUSE_BT0_SELECT		0x0100
+#define  EFUSE_BT1_SELECT		0x0200
+#define  EFUSE_BT2_SELECT		0x0300
+
+#define  EFUSE_ACCESS_ENABLE		0x69	/* RTL8723 only */
+#define  EFUSE_ACCESS_DISABLE		0x00	/* RTL8723 only */
+
+#define REG_PWR_DATA			0x0038
+#define REG_CAL_TIMER			0x003c
+#define REG_ACLK_MON			0x003e
+#define REG_GPIO_MUXCFG			0x0040
+#define REG_GPIO_IO_SEL			0x0042
+#define REG_MAC_PINMUX_CFG		0x0043
+#define REG_GPIO_PIN_CTRL		0x0044
+#define REG_GPIO_INTM			0x0048
+#define REG_LEDCFG0			0x004c
+#define REG_LEDCFG1			0x004d
+#define REG_LEDCFG2			0x004e
+#define  LEDCFG2_DPDT_SELECT		BIT(7)
+#define REG_LEDCFG3			0x004f
+#define REG_LEDCFG			REG_LEDCFG2
+#define REG_FSIMR			0x0050
+#define REG_FSISR			0x0054
+#define REG_HSIMR			0x0058
+#define REG_HSISR			0x005c
+/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */
+#define REG_GPIO_PIN_CTRL_2		0x0060
+/*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */
+#define REG_GPIO_IO_SEL_2		0x0062
+
+/*  RTL8723 only WIFI/BT/GPS Multi-Function control source. */
+#define REG_MULTI_FUNC_CTRL		0x0068
+
+#define  MULTI_FN_WIFI_HW_PWRDOWN_EN	BIT(0)	/* Enable GPIO[9] as WiFi HW
+						   powerdown source */
+#define  MULTI_FN_WIFI_HW_PWRDOWN_SL	BIT(1)	/* WiFi HW powerdown polarity
+						   control */
+#define  MULTI_WIFI_FUNC_EN		BIT(2)	/* WiFi function enable */
+
+#define  MULTI_WIFI_HW_ROF_EN		BIT(3)	/* Enable GPIO[9] as WiFi RF HW
+						   powerdown source */
+#define  MULTI_BT_HW_PWRDOWN_EN		BIT(16)	/* Enable GPIO[11] as BT HW
+						   powerdown source */
+#define  MULTI_BT_HW_PWRDOWN_SL		BIT(17)	/* BT HW powerdown polarity
+						   control */
+#define  MULTI_BT_FUNC_EN		BIT(18)	/* BT function enable */
+#define  MULTI_BT_HW_ROF_EN		BIT(19)	/* Enable GPIO[11] as BT/GPS
+						   RF HW powerdown source */
+#define  MULTI_GPS_HW_PWRDOWN_EN	BIT(20)	/* Enable GPIO[10] as GPS HW
+						   powerdown source */
+#define  MULTI_GPS_HW_PWRDOWN_SL	BIT(21)	/* GPS HW powerdown polarity
+						   control */
+#define  MULTI_GPS_FUNC_EN		BIT(22)	/* GPS function enable */
+
+#define REG_MCU_FW_DL			0x0080
+#define  MCU_FW_DL_ENABLE		BIT(0)
+#define  MCU_FW_DL_READY		BIT(1)
+#define  MCU_FW_DL_CSUM_REPORT		BIT(2)
+#define  MCU_MAC_INIT_READY		BIT(3)
+#define  MCU_BB_INIT_READY		BIT(4)
+#define  MCU_RF_INIT_READY		BIT(5)
+#define  MCU_WINT_INIT_READY		BIT(6)
+#define  MCU_FW_RAM_SEL			BIT(7)	/* 1: RAM, 0:ROM */
+#define  MCU_CP_RESET			BIT(23)
+
+#define REG_HMBOX_EXT_0			0x0088
+#define REG_HMBOX_EXT_1			0x008a
+#define REG_HMBOX_EXT_2			0x008c
+#define REG_HMBOX_EXT_3			0x008e
+/*  Host suspend counter on FPGA platform */
+#define REG_HOST_SUSP_CNT		0x00bc
+/*  Efuse access protection for RTL8723 */
+#define REG_EFUSE_ACCESS		0x00cf
+#define REG_BIST_SCAN			0x00d0
+#define REG_BIST_RPT			0x00d4
+#define REG_BIST_ROM_RPT		0x00d8
+#define REG_USB_SIE_INTF		0x00e0
+#define REG_PCIE_MIO_INTF		0x00e4
+#define REG_PCIE_MIO_INTD		0x00e8
+#define REG_HPON_FSM			0x00ec
+#define  HPON_FSM_BONDING_MASK		(BIT(22) | BIT(23))
+#define  HPON_FSM_BONDING_1T2R		BIT(22)
+#define REG_SYS_CFG			0x00f0
+#define  SYS_CFG_XCLK_VLD		BIT(0)
+#define  SYS_CFG_ACLK_VLD		BIT(1)
+#define  SYS_CFG_UCLK_VLD		BIT(2)
+#define  SYS_CFG_PCLK_VLD		BIT(3)
+#define  SYS_CFG_PCIRSTB		BIT(4)
+#define  SYS_CFG_V15_VLD		BIT(5)
+#define  SYS_CFG_TRP_B15V_EN		BIT(7)
+#define  SYS_CFG_SIC_IDLE		BIT(8)
+#define  SYS_CFG_BD_MAC2		BIT(9)
+#define  SYS_CFG_BD_MAC1		BIT(10)
+#define  SYS_CFG_IC_MACPHY_MODE		BIT(11)
+#define  SYS_CFG_CHIP_VER		(BIT(12) | BIT(13) | BIT(14) | BIT(15))
+#define  SYS_CFG_BT_FUNC		BIT(16)
+#define  SYS_CFG_VENDOR_ID		BIT(19)
+#define  SYS_CFG_PAD_HWPD_IDN		BIT(22)
+#define  SYS_CFG_TRP_VAUX_EN		BIT(23)
+#define  SYS_CFG_TRP_BT_EN		BIT(24)
+#define  SYS_CFG_BD_PKG_SEL		BIT(25)
+#define  SYS_CFG_BD_HCI_SEL		BIT(26)
+#define  SYS_CFG_TYPE_ID		BIT(27)
+#define  SYS_CFG_RTL_ID			BIT(23) /*  TestChip ID,
+						    1:Test(RLE); 0:MP(RL) */
+#define  SYS_CFG_SPS_SEL		BIT(24) /*  1:LDO regulator mode;
+						    0:Switching regulator mode*/
+#define  SYS_CFG_CHIP_VERSION_MASK	0xf000	/* Bit 12 - 15 */
+#define  SYS_CFG_CHIP_VERSION_SHIFT	12
+
+#define REG_GPIO_OUTSTS			0x00f4	/*  For RTL8723 only. */
+#define  GPIO_EFS_HCI_SEL		(BIT(0) | BIT(1))
+#define  GPIO_PAD_HCI_SEL		(BIT(2) | BIT(3))
+#define  GPIO_HCI_SEL			(BIT(4) | BIT(5))
+#define  GPIO_PKG_SEL_HCI		BIT(6)
+#define  GPIO_FEN_GPS			BIT(7)
+#define  GPIO_FEN_BT			BIT(8)
+#define  GPIO_FEN_WL			BIT(9)
+#define  GPIO_FEN_PCI			BIT(10)
+#define  GPIO_FEN_USB			BIT(11)
+#define  GPIO_BTRF_HWPDN_N		BIT(12)
+#define  GPIO_WLRF_HWPDN_N		BIT(13)
+#define  GPIO_PDN_BT_N			BIT(14)
+#define  GPIO_PDN_GPS_N			BIT(15)
+#define  GPIO_BT_CTL_HWPDN		BIT(16)
+#define  GPIO_GPS_CTL_HWPDN		BIT(17)
+#define  GPIO_PPHY_SUSB			BIT(20)
+#define  GPIO_UPHY_SUSB			BIT(21)
+#define  GPIO_PCI_SUSEN			BIT(22)
+#define  GPIO_USB_SUSEN			BIT(23)
+#define  GPIO_RF_RL_ID			(BIT(31) | BIT(30) | BIT(29) | BIT(28))
+
+/* 0x0100 ~ 0x01FF	MACTOP General Configuration */
+#define REG_CR				0x0100
+#define  CR_HCI_TXDMA_ENABLE		BIT(0)
+#define  CR_HCI_RXDMA_ENABLE		BIT(1)
+#define  CR_TXDMA_ENABLE		BIT(2)
+#define  CR_RXDMA_ENABLE		BIT(3)
+#define  CR_PROTOCOL_ENABLE		BIT(4)
+#define  CR_SCHEDULE_ENABLE		BIT(5)
+#define  CR_MAC_TX_ENABLE		BIT(6)
+#define  CR_MAC_RX_ENABLE		BIT(7)
+#define  CR_SW_BEACON_ENABLE		BIT(8)
+#define  CR_SECURITY_ENABLE		BIT(9)
+#define  CR_CALTIMER_ENABLE		BIT(10)
+
+/* Media Status Register */
+#define REG_MSR				0x0102
+#define  MSR_LINKTYPE_MASK		0x3
+#define  MSR_LINKTYPE_NONE		0x0
+#define  MSR_LINKTYPE_ADHOC		0x1
+#define  MSR_LINKTYPE_STATION		0x2
+#define  MSR_LINKTYPE_AP		0x3
+
+#define REG_PBP				0x0104
+#define  PBP_PAGE_SIZE_RX_SHIFT		0
+#define  PBP_PAGE_SIZE_TX_SHIFT		4
+#define  PBP_PAGE_SIZE_64		0x0
+#define  PBP_PAGE_SIZE_128		0x1
+#define  PBP_PAGE_SIZE_256		0x2
+#define  PBP_PAGE_SIZE_512		0x3
+#define  PBP_PAGE_SIZE_1024		0x4
+
+#define REG_TRXDMA_CTRL			0x010c
+#define  TRXDMA_CTRL_VOQ_SHIFT		4
+#define  TRXDMA_CTRL_VIQ_SHIFT		6
+#define  TRXDMA_CTRL_BEQ_SHIFT		8
+#define  TRXDMA_CTRL_BKQ_SHIFT		10
+#define  TRXDMA_CTRL_MGQ_SHIFT		12
+#define  TRXDMA_CTRL_HIQ_SHIFT		14
+#define  TRXDMA_QUEUE_LOW		1
+#define  TRXDMA_QUEUE_NORMAL		2
+#define  TRXDMA_QUEUE_HIGH		3
+
+#define REG_TRXFF_BNDY			0x0114
+#define REG_TRXFF_STATUS		0x0118
+#define REG_RXFF_PTR			0x011c
+#define REG_HIMR			0x0120
+#define REG_HISR			0x0124
+#define REG_HIMRE			0x0128
+#define REG_HISRE			0x012c
+#define REG_CPWM			0x012f
+#define REG_FWIMR			0x0130
+#define REG_FWISR			0x0134
+#define REG_PKTBUF_DBG_CTRL		0x0140
+#define REG_PKTBUF_DBG_DATA_L		0x0144
+#define REG_PKTBUF_DBG_DATA_H		0x0148
+
+#define REG_TC0_CTRL			0x0150
+#define REG_TC1_CTRL			0x0154
+#define REG_TC2_CTRL			0x0158
+#define REG_TC3_CTRL			0x015c
+#define REG_TC4_CTRL			0x0160
+#define REG_TCUNIT_BASE			0x0164
+#define REG_MBIST_START			0x0174
+#define REG_MBIST_DONE			0x0178
+#define REG_MBIST_FAIL			0x017c
+#define REG_C2HEVT_MSG_NORMAL		0x01a0
+#define REG_C2HEVT_CLEAR		0x01af
+#define REG_C2HEVT_MSG_TEST		0x01b8
+#define REG_MCUTST_1			0x01c0
+#define REG_FMTHR			0x01c8
+#define REG_HMTFR			0x01cc
+#define REG_HMBOX_0			0x01d0
+#define REG_HMBOX_1			0x01d4
+#define REG_HMBOX_2			0x01d8
+#define REG_HMBOX_3			0x01dc
+
+#define REG_LLT_INIT			0x01e0
+#define  LLT_OP_INACTIVE		0x0
+#define  LLT_OP_WRITE			(0x1 << 30)
+#define  LLT_OP_READ			(0x2 << 30)
+#define  LLT_OP_MASK			(0x3 << 30)
+
+#define REG_BB_ACCEESS_CTRL		0x01e8
+#define REG_BB_ACCESS_DATA		0x01ec
+
+/* 0x0200 ~ 0x027F	TXDMA Configuration */
+#define REG_RQPN			0x0200
+#define  RQPN_HI_PQ_SHIFT		0
+#define  RQPN_LO_PQ_SHIFT		8
+#define  RQPN_NORM_PQ_SHIFT		16
+#define  RQPN_LOAD			BIT(31)
+
+#define REG_FIFOPAGE			0x0204
+#define REG_TDECTRL			0x0208
+#define REG_TXDMA_OFFSET_CHK		0x020c
+#define REG_TXDMA_STATUS		0x0210
+#define REG_RQPN_NPQ			0x0214
+
+/* 0x0280 ~ 0x02FF	RXDMA Configuration */
+#define REG_RXDMA_AGG_PG_TH		0x0280
+#define REG_RXPKT_NUM			0x0284
+#define REG_RXDMA_STATUS		0x0288
+
+#define REG_RF_BB_CMD_ADDR		0x02c0
+#define REG_RF_BB_CMD_DATA		0x02c4
+
+/*  spec version 11 */
+/* 0x0400 ~ 0x047F	Protocol Configuration */
+#define REG_VOQ_INFORMATION		0x0400
+#define REG_VIQ_INFORMATION		0x0404
+#define REG_BEQ_INFORMATION		0x0408
+#define REG_BKQ_INFORMATION		0x040c
+#define REG_MGQ_INFORMATION		0x0410
+#define REG_HGQ_INFORMATION		0x0414
+#define REG_BCNQ_INFORMATION		0x0418
+
+#define REG_CPU_MGQ_INFORMATION		0x041c
+#define REG_FWHW_TXQ_CTRL		0x0420
+#define  FWHW_TXQ_CTRL_AMPDU_RETRY	BIT(7)
+#define  FWHW_TXQ_CTRL_XMIT_MGMT_ACK	BIT(12)
+
+#define REG_HWSEQ_CTRL			0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY		0x0424
+#define REG_TXPKTBUF_MGQ_BDNY		0x0425
+#define REG_LIFETIME_EN			0x0426
+#define REG_MULTI_BCNQ_OFFSET		0x0427
+
+#define REG_SPEC_SIFS			0x0428
+#define  SPEC_SIFS_CCK_MASK		0x00ff
+#define  SPEC_SIFS_CCK_SHIFT		0
+#define  SPEC_SIFS_OFDM_MASK		0xff00
+#define  SPEC_SIFS_OFDM_SHIFT		8
+
+#define REG_RETRY_LIMIT			0x042a
+#define  RETRY_LIMIT_LONG_SHIFT		0
+#define  RETRY_LIMIT_LONG_MASK		0x003f
+#define  RETRY_LIMIT_SHORT_SHIFT	8
+#define  RETRY_LIMIT_SHORT_MASK		0x3f00
+
+#define REG_DARFRC			0x0430
+#define REG_RARFRC			0x0438
+#define REG_RESPONSE_RATE_SET		0x0440
+#define  RESPONSE_RATE_BITMAP_ALL	0xfffff
+#define  RESPONSE_RATE_RRSR_CCK_ONLY_1M	0xffff1
+#define  RSR_1M				BIT(0)
+#define  RSR_2M				BIT(1)
+#define  RSR_5_5M			BIT(2)
+#define  RSR_11M			BIT(3)
+#define  RSR_6M				BIT(4)
+#define  RSR_9M				BIT(5)
+#define  RSR_12M			BIT(6)
+#define  RSR_18M			BIT(7)
+#define  RSR_24M			BIT(8)
+#define  RSR_36M			BIT(9)
+#define  RSR_48M			BIT(10)
+#define  RSR_54M			BIT(11)
+#define  RSR_MCS0			BIT(12)
+#define  RSR_MCS1			BIT(13)
+#define  RSR_MCS2			BIT(14)
+#define  RSR_MCS3			BIT(15)
+#define  RSR_MCS4			BIT(16)
+#define  RSR_MCS5			BIT(17)
+#define  RSR_MCS6			BIT(18)
+#define  RSR_MCS7			BIT(19)
+#define  RSR_RSC_LOWER_SUB_CHANNEL	BIT(21)	/* 0x200000 */
+#define  RSR_RSC_UPPER_SUB_CHANNEL	BIT(22)	/* 0x400000 */
+#define  RSR_RSC_BANDWIDTH_40M		(RSR_RSC_UPPER_SUB_CHANNEL | \
+					 RSR_RSC_LOWER_SUB_CHANNEL)
+#define  RSR_ACK_SHORT_PREAMBLE		BIT(23)
+
+#define REG_ARFR0			0x0444
+#define REG_ARFR1			0x0448
+#define REG_ARFR2			0x044c
+#define REG_ARFR3			0x0450
+#define REG_AGGLEN_LMT			0x0458
+#define REG_AMPDU_MIN_SPACE		0x045c
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD	0x045d
+#define REG_FAST_EDCA_CTRL		0x0460
+#define REG_RD_RESP_PKT_TH		0x0463
+#define REG_INIRTS_RATE_SEL		0x0480
+#define REG_INIDATA_RATE_SEL		0x0484
+
+#define REG_POWER_STATUS		0x04a4
+#define REG_POWER_STAGE1		0x04b4
+#define REG_POWER_STAGE2		0x04b8
+#define REG_PKT_VO_VI_LIFE_TIME		0x04c0
+#define REG_PKT_BE_BK_LIFE_TIME		0x04c2
+#define REG_STBC_SETTING		0x04c4
+#define REG_PROT_MODE_CTRL		0x04c8
+#define REG_MAX_AGGR_NUM		0x04ca
+#define REG_RTS_MAX_AGGR_NUM		0x04cb
+#define REG_BAR_MODE_CTRL		0x04cc
+#define REG_RA_TRY_RATE_AGG_LMT		0x04cf
+#define REG_NQOS_SEQ			0x04dc
+#define REG_QOS_SEQ			0x04de
+#define REG_NEED_CPU_HANDLE		0x04e0
+#define REG_PKT_LOSE_RPT		0x04e1
+#define REG_PTCL_ERR_STATUS		0x04e2
+#define REG_DUMMY			0x04fc
+
+/* 0x0500 ~ 0x05FF	EDCA Configuration */
+#define REG_EDCA_VO_PARAM		0x0500
+#define REG_EDCA_VI_PARAM		0x0504
+#define REG_EDCA_BE_PARAM		0x0508
+#define REG_EDCA_BK_PARAM		0x050c
+#define  EDCA_PARAM_ECW_MIN_SHIFT	8
+#define  EDCA_PARAM_ECW_MAX_SHIFT	12
+#define  EDCA_PARAM_TXOP_SHIFT		16
+#define REG_BEACON_TCFG			0x0510
+#define REG_PIFS			0x0512
+#define REG_RDG_PIFS			0x0513
+#define REG_SIFS_CCK			0x0514
+#define REG_SIFS_OFDM			0x0516
+#define REG_TSFTR_SYN_OFFSET		0x0518
+#define REG_AGGR_BREAK_TIME		0x051a
+#define REG_SLOT			0x051b
+#define REG_TX_PTCL_CTRL		0x0520
+#define REG_TXPAUSE			0x0522
+#define REG_DIS_TXREQ_CLR		0x0523
+#define REG_RD_CTRL			0x0524
+#define REG_TBTT_PROHIBIT		0x0540
+#define REG_RD_NAV_NXT			0x0544
+#define REG_NAV_PROT_LEN		0x0546
+
+#define REG_BEACON_CTRL			0x0550
+#define REG_BEACON_CTRL_1		0x0551
+#define  BEACON_ATIM			BIT(0)
+#define  BEACON_CTRL_MBSSID		BIT(1)
+#define  BEACON_CTRL_TX_BEACON_RPT	BIT(2)
+#define  BEACON_FUNCTION_ENABLE		BIT(3)
+#define  BEACON_DISABLE_TSF_UPDATE	BIT(4)
+
+#define REG_MBID_NUM			0x0552
+#define REG_DUAL_TSF_RST		0x0553
+#define  DUAL_TSF_RESET_TSF0		BIT(0)
+#define  DUAL_TSF_RESET_TSF1		BIT(1)
+#define  DUAL_TSF_RESET_P2P		BIT(4)
+#define  DUAL_TSF_TX_OK			BIT(5)
+
+/*  The same as REG_MBSSID_BCN_SPACE */
+#define REG_BCN_INTERVAL		0x0554
+#define REG_MBSSID_BCN_SPACE		0x0554
+
+#define REG_DRIVER_EARLY_INT		0x0558
+#define  DRIVER_EARLY_INT_TIME		5
+
+#define REG_BEACON_DMA_TIME		0x0559
+#define  BEACON_DMA_ATIME_INT_TIME	2
+
+#define REG_ATIMWND			0x055a
+#define REG_BCN_MAX_ERR			0x055d
+#define REG_RXTSF_OFFSET_CCK		0x055e
+#define REG_RXTSF_OFFSET_OFDM		0x055f
+#define REG_TSFTR			0x0560
+#define REG_TSFTR1			0x0568
+#define REG_INIT_TSFTR			0x0564
+#define REG_ATIMWND_1			0x0570
+#define REG_PSTIMER			0x0580
+#define REG_TIMER0			0x0584
+#define REG_TIMER1			0x0588
+#define REG_ACM_HW_CTRL			0x05c0
+#define  ACM_HW_CTRL_BK			BIT(0)
+#define  ACM_HW_CTRL_BE			BIT(1)
+#define  ACM_HW_CTRL_VI			BIT(2)
+#define  ACM_HW_CTRL_VO			BIT(3)
+#define REG_ACM_RST_CTRL		0x05c1
+#define REG_ACMAVG			0x05c2
+#define REG_VO_ADMTIME			0x05c4
+#define REG_VI_ADMTIME			0x05c6
+#define REG_BE_ADMTIME			0x05c8
+#define REG_EDCA_RANDOM_GEN		0x05cc
+#define REG_SCH_TXCMD			0x05d0
+
+/* define REG_FW_TSF_SYNC_CNT		0x04a0 */
+#define REG_FW_RESET_TSF_CNT_1		0x05fc
+#define REG_FW_RESET_TSF_CNT_0		0x05fd
+#define REG_FW_BCN_DIS_CNT		0x05fe
+
+/* 0x0600 ~ 0x07FF  WMAC Configuration */
+#define REG_APSD_CTRL			0x0600
+#define  APSD_CTRL_OFF			BIT(6)
+#define  APSD_CTRL_OFF_STATUS		BIT(7)
+#define REG_BW_OPMODE			0x0603
+#define  BW_OPMODE_20MHZ		BIT(2)
+#define  BW_OPMODE_5G			BIT(1)
+#define  BW_OPMODE_11J			BIT(0)
+
+#define REG_TCR				0x0604
+
+/* Receive Configuration Register */
+#define REG_RCR				0x0608
+#define  RCR_ACCEPT_AP			BIT(0)  /* Accept all unicast packet */
+#define  RCR_ACCEPT_PHYS_MATCH		BIT(1)  /* Accept phys match packet */
+#define  RCR_ACCEPT_MCAST		BIT(2)
+#define  RCR_ACCEPT_BCAST		BIT(3)
+#define  RCR_ACCEPT_ADDR3		BIT(4)  /* Accept address 3 match
+						 packet */
+#define  RCR_ACCEPT_PM			BIT(5)  /* Accept power management
+						 packet */
+#define  RCR_CHECK_BSSID_MATCH		BIT(6)  /* Accept BSSID match packet */
+#define  RCR_CHECK_BSSID_BEACON		BIT(7)  /* Accept BSSID match packet
+						 (Rx beacon, probe rsp) */
+#define  RCR_ACCEPT_CRC32		BIT(8)  /* Accept CRC32 error packet */
+#define  RCR_ACCEPT_ICV			BIT(9)  /* Accept ICV error packet */
+#define  RCR_ACCEPT_DATA_FRAME		BIT(11)
+#define  RCR_ACCEPT_CTRL_FRAME		BIT(12)
+#define  RCR_ACCEPT_MGMT_FRAME		BIT(13)
+#define  RCR_HTC_LOC_CTRL		BIT(14) /* MFC<--HTC=1 MFC-->HTC=0 */
+#define  RCR_MFBEN			BIT(22)
+#define  RCR_LSIGEN			BIT(23)
+#define  RCR_MULTI_BSSID_ENABLE		BIT(24) /* Enable Multiple BssId */
+#define  RCR_ACCEPT_BA_SSN		BIT(27) /* Accept BA SSN */
+#define  RCR_APPEND_PHYSTAT		BIT(28)
+#define  RCR_APPEND_ICV			BIT(29)
+#define  RCR_APPEND_MIC			BIT(30)
+#define  RCR_APPEND_FCS			BIT(31) /* WMAC append FCS after */
+
+#define REG_RX_PKT_LIMIT		0x060c
+#define REG_RX_DLK_TIME			0x060d
+#define REG_RX_DRVINFO_SZ		0x060f
+
+#define REG_MACID			0x0610
+#define REG_BSSID			0x0618
+#define REG_MAR				0x0620
+#define REG_MBIDCAMCFG			0x0628
+
+#define REG_USTIME_EDCA			0x0638
+#define REG_MAC_SPEC_SIFS		0x063a
+
+/*  20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
+	/*  [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
+#define REG_R2T_SIFS			0x063c
+	/*  [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
+#define REG_T2T_SIFS			0x063e
+#define REG_ACKTO			0x0640
+#define REG_CTS2TO			0x0641
+#define REG_EIFS			0x0642
+
+/* WMA, BA, CCX */
+#define REG_NAV_CTRL			0x0650
+/* In units of 128us */
+#define REG_NAV_UPPER			0x0652
+#define  NAV_UPPER_UNIT			128
+
+#define REG_BACAMCMD			0x0654
+#define REG_BACAMCONTENT		0x0658
+#define REG_LBDLY			0x0660
+#define REG_FWDLY			0x0661
+#define REG_RXERR_RPT			0x0664
+#define REG_WMAC_TRXPTCL_CTL		0x0668
+
+/*  Security */
+#define REG_CAM_CMD			0x0670
+#define  CAM_CMD_POLLING		BIT(31)
+#define  CAM_CMD_WRITE			BIT(16)
+#define  CAM_CMD_KEY_SHIFT		3
+#define REG_CAM_WRITE			0x0674
+#define  CAM_WRITE_VALID		BIT(15)
+#define REG_CAM_READ			0x0678
+#define REG_CAM_DEBUG			0x067c
+#define REG_SECURITY_CFG		0x0680
+#define  SEC_CFG_TX_USE_DEFKEY		BIT(0)
+#define  SEC_CFG_RX_USE_DEFKEY		BIT(1)
+#define  SEC_CFG_TX_SEC_ENABLE		BIT(2)
+#define  SEC_CFG_RX_SEC_ENABLE		BIT(3)
+#define  SEC_CFG_SKBYA2			BIT(4)
+#define  SEC_CFG_NO_SKMC		BIT(5)
+#define  SEC_CFG_TXBC_USE_DEFKEY	BIT(6)
+#define  SEC_CFG_RXBC_USE_DEFKEY	BIT(7)
+
+/*  Power */
+#define REG_WOW_CTRL			0x0690
+#define REG_PSSTATUS			0x0691
+#define REG_PS_RX_INFO			0x0692
+#define REG_LPNAV_CTRL			0x0694
+#define REG_WKFMCAM_CMD			0x0698
+#define REG_WKFMCAM_RWD			0x069c
+#define REG_RXFLTMAP0			0x06a0
+#define REG_RXFLTMAP1			0x06a2
+#define REG_RXFLTMAP2			0x06a4
+#define REG_BCN_PSR_RPT			0x06a8
+#define REG_CALB32K_CTRL		0x06ac
+#define REG_PKT_MON_CTRL		0x06b4
+#define REG_BT_COEX_TABLE		0x06c0
+#define REG_WMAC_RESP_TXINFO		0x06d8
+
+#define REG_MACID1			0x0700
+#define REG_BSSID1			0x0708
+
+#define REG_FPGA0_RF_MODE		0x0800
+#define  FPGA_RF_MODE			BIT(0)
+#define  FPGA_RF_MODE_JAPAN		BIT(1)
+#define  FPGA_RF_MODE_CCK		BIT(24)
+#define  FPGA_RF_MODE_OFDM		BIT(25)
+
+#define REG_FPGA0_TX_INFO		0x0804
+#define REG_FPGA0_PSD_FUNC		0x0808
+#define REG_FPGA0_TX_GAIN		0x080c
+#define REG_FPGA0_RF_TIMING1		0x0810
+#define REG_FPGA0_RF_TIMING2		0x0814
+#define REG_FPGA0_POWER_SAVE		0x0818
+#define  FPGA0_PS_LOWER_CHANNEL		BIT(26)
+#define  FPGA0_PS_UPPER_CHANNEL		BIT(27)
+
+#define REG_FPGA0_XA_HSSI_PARM1		0x0820	/* RF 3 wire register */
+#define  FPGA0_HSSI_PARM1_PI		BIT(8)
+#define REG_FPGA0_XA_HSSI_PARM2		0x0824
+#define REG_FPGA0_XB_HSSI_PARM1		0x0828
+#define REG_FPGA0_XB_HSSI_PARM2		0x082c
+#define  FPGA0_HSSI_3WIRE_DATA_LEN	0x800
+#define  FPGA0_HSSI_3WIRE_ADDR_LEN	0x400
+#define  FPGA0_HSSI_PARM2_ADDR_SHIFT	23
+#define  FPGA0_HSSI_PARM2_ADDR_MASK	0x7f800000	/* 0xff << 23 */
+#define  FPGA0_HSSI_PARM2_CCK_HIGH_PWR	BIT(9)
+#define  FPGA0_HSSI_PARM2_EDGE_READ	BIT(31)
+
+#define REG_TX_AGC_B_RATE18_06		0x0830
+#define REG_TX_AGC_B_RATE54_24		0x0834
+#define REG_TX_AGC_B_CCK1_55_MCS32	0x0838
+#define REG_TX_AGC_B_MCS03_MCS00	0x083c
+
+#define REG_FPGA0_XA_LSSI_PARM		0x0840
+#define REG_FPGA0_XB_LSSI_PARM		0x0844
+#define  FPGA0_LSSI_PARM_ADDR_SHIFT	20
+#define  FPGA0_LSSI_PARM_ADDR_MASK	0x0ff00000
+#define  FPGA0_LSSI_PARM_DATA_MASK	0x000fffff
+
+#define REG_TX_AGC_B_MCS07_MCS04	0x0848
+#define REG_TX_AGC_B_MCS11_MCS08	0x084c
+
+#define REG_FPGA0_XCD_SWITCH_CTRL	0x085c
+
+#define REG_FPGA0_XA_RF_INT_OE		0x0860	/* RF Channel switch */
+#define REG_FPGA0_XB_RF_INT_OE		0x0864
+#define  FPGA0_INT_OE_ANTENNA_AB_OPEN	0x000
+#define  FPGA0_INT_OE_ANTENNA_A		BIT(8)
+#define  FPGA0_INT_OE_ANTENNA_B		BIT(9)
+#define  FPGA0_INT_OE_ANTENNA_MASK	(FPGA0_INT_OE_ANTENNA_A | \
+					 FPGA0_INT_OE_ANTENNA_B)
+
+#define REG_TX_AGC_B_MCS15_MCS12	0x0868
+#define REG_TX_AGC_B_CCK11_A_CCK2_11	0x086c
+
+#define REG_FPGA0_XAB_RF_SW_CTRL	0x0870
+#define REG_FPGA0_XA_RF_SW_CTRL		0x0870	/* 16 bit */
+#define REG_FPGA0_XB_RF_SW_CTRL		0x0872	/* 16 bit */
+#define REG_FPGA0_XCD_RF_SW_CTRL	0x0874
+#define REG_FPGA0_XC_RF_SW_CTRL		0x0874	/* 16 bit */
+#define REG_FPGA0_XD_RF_SW_CTRL		0x0876	/* 16 bit */
+#define  FPGA0_RF_3WIRE_DATA		BIT(0)
+#define  FPGA0_RF_3WIRE_CLOC		BIT(1)
+#define  FPGA0_RF_3WIRE_LOAD		BIT(2)
+#define  FPGA0_RF_3WIRE_RW		BIT(3)
+#define  FPGA0_RF_3WIRE_MASK		0xf
+#define  FPGA0_RF_RFENV			BIT(4)
+#define  FPGA0_RF_TRSW			BIT(5)	/* Useless now */
+#define  FPGA0_RF_TRSWB			BIT(6)
+#define  FPGA0_RF_ANTSW			BIT(8)
+#define  FPGA0_RF_ANTSWB		BIT(9)
+#define  FPGA0_RF_PAPE			BIT(10)
+#define  FPGA0_RF_PAPE5G		BIT(11)
+#define  FPGA0_RF_BD_CTRL_SHIFT		16
+
+#define REG_FPGA0_XAB_RF_PARM		0x0878	/* Antenna select path in ODM */
+#define REG_FPGA0_XA_RF_PARM		0x0878	/* 16 bit */
+#define REG_FPGA0_XB_RF_PARM		0x087a	/* 16 bit */
+#define REG_FPGA0_XCD_RF_PARM		0x087c
+#define REG_FPGA0_XC_RF_PARM		0x087c	/* 16 bit */
+#define REG_FPGA0_XD_RF_PARM		0x087e	/* 16 bit */
+#define  FPGA0_RF_PARM_RFA_ENABLE	BIT(1)
+#define  FPGA0_RF_PARM_RFB_ENABLE	BIT(17)
+#define  FPGA0_RF_PARM_CLK_GATE		BIT(31)
+
+#define REG_FPGA0_ANALOG1		0x0880
+#define REG_FPGA0_ANALOG2		0x0884
+#define  FPGA0_ANALOG2_20MHZ		BIT(10)
+#define REG_FPGA0_ANALOG3		0x0888
+#define REG_FPGA0_ANALOG4		0x088c
+
+#define REG_FPGA0_XA_LSSI_READBACK	0x08a0	/* Tranceiver LSSI Readback */
+#define REG_FPGA0_XB_LSSI_READBACK	0x08a4
+#define REG_HSPI_XA_READBACK		0x08b8	/* Transceiver A HSPI read */
+#define REG_HSPI_XB_READBACK		0x08bc	/* Transceiver B HSPI read */
+
+#define REG_FPGA1_RF_MODE		0x0900
+
+#define REG_FPGA1_TX_INFO		0x090c
+
+#define REG_CCK0_SYSTEM			0x0a00
+#define  CCK0_SIDEBAND			BIT(4)
+
+#define REG_CCK0_AFE_SETTING		0x0a04
+
+#define REG_CONFIG_ANT_A		0x0b68
+#define REG_CONFIG_ANT_B		0x0b6c
+
+#define REG_OFDM0_TRX_PATH_ENABLE	0x0c04
+#define OFDM_RF_PATH_RX_MASK		0x0f
+#define OFDM_RF_PATH_RX_A		BIT(0)
+#define OFDM_RF_PATH_RX_B		BIT(1)
+#define OFDM_RF_PATH_RX_C		BIT(2)
+#define OFDM_RF_PATH_RX_D		BIT(3)
+#define OFDM_RF_PATH_TX_MASK		0xf0
+#define OFDM_RF_PATH_TX_A		BIT(4)
+#define OFDM_RF_PATH_TX_B		BIT(5)
+#define OFDM_RF_PATH_TX_C		BIT(6)
+#define OFDM_RF_PATH_TX_D		BIT(7)
+
+#define REG_OFDM0_TR_MUX_PAR		0x0c08
+
+#define REG_OFDM0_XA_RX_IQ_IMBALANCE	0x0c14
+#define REG_OFDM0_XB_RX_IQ_IMBALANCE	0x0c1c
+
+#define REG_OFDM0_ENERGY_CCA_THRES	0x0c4c
+
+#define REG_OFDM0_XA_AGC_CORE1		0x0c50
+#define REG_OFDM0_XA_AGC_CORE2		0x0c54
+#define REG_OFDM0_XB_AGC_CORE1		0x0c58
+#define REG_OFDM0_XB_AGC_CORE2		0x0c5c
+#define REG_OFDM0_XC_AGC_CORE1		0x0c60
+#define REG_OFDM0_XC_AGC_CORE2		0x0c64
+#define REG_OFDM0_XD_AGC_CORE1		0x0c68
+#define REG_OFDM0_XD_AGC_CORE2		0x0c6c
+#define  OFDM0_X_AGC_CORE1_IGI_MASK	0x0000007F
+
+#define REG_OFDM0_AGC_PARM1		0x0c70
+
+#define REG_OFDM0_AGCR_SSI_TABLE	0x0c78
+
+#define REG_OFDM0_XA_TX_IQ_IMBALANCE	0x0c80
+#define REG_OFDM0_XB_TX_IQ_IMBALANCE	0x0c88
+#define REG_OFDM0_XC_TX_IQ_IMBALANCE	0x0c90
+#define REG_OFDM0_XD_TX_IQ_IMBALANCE	0x0c98
+
+#define REG_OFDM0_XC_TX_AFE		0x0c94
+#define REG_OFDM0_XD_TX_AFE		0x0c9c
+
+#define REG_OFDM0_RX_IQ_EXT_ANTA	0x0ca0
+
+#define REG_OFDM1_LSTF			0x0d00
+#define  OFDM_LSTF_PRIME_CH_LOW		BIT(10)
+#define  OFDM_LSTF_PRIME_CH_HIGH	BIT(11)
+#define  OFDM_LSTF_PRIME_CH_MASK	(OFDM_LSTF_PRIME_CH_LOW | \
+					 OFDM_LSTF_PRIME_CH_HIGH)
+#define  OFDM_LSTF_CONTINUE_TX		BIT(28)
+#define  OFDM_LSTF_SINGLE_CARRIER	BIT(29)
+#define  OFDM_LSTF_SINGLE_TONE		BIT(30)
+#define  OFDM_LSTF_MASK			0x70000000
+
+#define REG_OFDM1_TRX_PATH_ENABLE	0x0d04
+
+#define REG_TX_AGC_A_RATE18_06		0x0e00
+#define REG_TX_AGC_A_RATE54_24		0x0e04
+#define REG_TX_AGC_A_CCK1_MCS32		0x0e08
+#define REG_TX_AGC_A_MCS03_MCS00	0x0e10
+#define REG_TX_AGC_A_MCS07_MCS04	0x0e14
+#define REG_TX_AGC_A_MCS11_MCS08	0x0e18
+#define REG_TX_AGC_A_MCS15_MCS12	0x0e1c
+
+#define REG_FPGA0_IQK			0x0e28
+
+#define REG_TX_IQK_TONE_A		0x0e30
+#define REG_RX_IQK_TONE_A		0x0e34
+#define REG_TX_IQK_PI_A			0x0e38
+#define REG_RX_IQK_PI_A			0x0e3c
+
+#define REG_TX_IQK			0x0e40
+#define REG_RX_IQK			0x0e44
+#define REG_IQK_AGC_PTS			0x0e48
+#define REG_IQK_AGC_RSP			0x0e4c
+#define REG_TX_IQK_TONE_B		0x0e50
+#define REG_RX_IQK_TONE_B		0x0e54
+#define REG_TX_IQK_PI_B			0x0e58
+#define REG_RX_IQK_PI_B			0x0e5c
+#define REG_IQK_AGC_CONT		0x0e60
+
+#define REG_BLUETOOTH			0x0e6c
+#define REG_RX_WAIT_CCA			0x0e70
+#define REG_TX_CCK_RFON			0x0e74
+#define REG_TX_CCK_BBON			0x0e78
+#define REG_TX_OFDM_RFON		0x0e7c
+#define REG_TX_OFDM_BBON		0x0e80
+#define REG_TX_TO_RX			0x0e84
+#define REG_TX_TO_TX			0x0e88
+#define REG_RX_CCK			0x0e8c
+
+#define REG_TX_POWER_BEFORE_IQK_A	0x0e94
+#define REG_TX_POWER_AFTER_IQK_A	0x0e9c
+
+#define REG_RX_POWER_BEFORE_IQK_A	0x0ea0
+#define REG_RX_POWER_BEFORE_IQK_A_2	0x0ea4
+#define REG_RX_POWER_AFTER_IQK_A	0x0ea8
+#define REG_RX_POWER_AFTER_IQK_A_2	0x0eac
+
+#define REG_TX_POWER_BEFORE_IQK_B	0x0eb4
+#define REG_TX_POWER_AFTER_IQK_B	0x0ebc
+
+#define REG_RX_POWER_BEFORE_IQK_B	0x0ec0
+#define REG_RX_POWER_BEFORE_IQK_B_2	0x0ec4
+#define REG_RX_POWER_AFTER_IQK_B	0x0ec8
+#define REG_RX_POWER_AFTER_IQK_B_2	0x0ecc
+
+#define REG_RX_OFDM			0x0ed0
+#define REG_RX_WAIT_RIFS		0x0ed4
+#define REG_RX_TO_RX			0x0ed8
+#define REG_STANDBY			0x0edc
+#define REG_SLEEP			0x0ee0
+#define REG_PMPD_ANAEN			0x0eec
+
+#define REG_FW_START_ADDRESS		0x1000
+
+#define REG_USB_INFO			0xfe17
+#define REG_USB_HIMR			0xfe38
+#define  USB_HIMR_TIMEOUT2		BIT(31)
+#define  USB_HIMR_TIMEOUT1		BIT(30)
+#define  USB_HIMR_PSTIMEOUT		BIT(29)
+#define  USB_HIMR_GTINT4		BIT(28)
+#define  USB_HIMR_GTINT3		BIT(27)
+#define  USB_HIMR_TXBCNERR		BIT(26)
+#define  USB_HIMR_TXBCNOK		BIT(25)
+#define  USB_HIMR_TSF_BIT32_TOGGLE	BIT(24)
+#define  USB_HIMR_BCNDMAINT3		BIT(23)
+#define  USB_HIMR_BCNDMAINT2		BIT(22)
+#define  USB_HIMR_BCNDMAINT1		BIT(21)
+#define  USB_HIMR_BCNDMAINT0		BIT(20)
+#define  USB_HIMR_BCNDOK3		BIT(19)
+#define  USB_HIMR_BCNDOK2		BIT(18)
+#define  USB_HIMR_BCNDOK1		BIT(17)
+#define  USB_HIMR_BCNDOK0		BIT(16)
+#define  USB_HIMR_HSISR_IND		BIT(15)
+#define  USB_HIMR_BCNDMAINT_E		BIT(14)
+/* RSVD	BIT(13) */
+#define  USB_HIMR_CTW_END		BIT(12)
+/* RSVD	BIT(11) */
+#define  USB_HIMR_C2HCMD		BIT(10)
+#define  USB_HIMR_CPWM2			BIT(9)
+#define  USB_HIMR_CPWM			BIT(8)
+#define  USB_HIMR_HIGHDOK		BIT(7)	/*  High Queue DMA OK
+						    Interrupt */
+#define  USB_HIMR_MGNTDOK		BIT(6)	/*  Management Queue DMA OK
+						    Interrupt */
+#define  USB_HIMR_BKDOK			BIT(5)	/*  AC_BK DMA OK Interrupt */
+#define  USB_HIMR_BEDOK			BIT(4)	/*  AC_BE DMA OK Interrupt */
+#define  USB_HIMR_VIDOK			BIT(3)	/*  AC_VI DMA OK Interrupt */
+#define  USB_HIMR_VODOK			BIT(2)	/*  AC_VO DMA Interrupt */
+#define  USB_HIMR_RDU			BIT(1)	/*  Receive Descriptor
+						    Unavailable */
+#define  USB_HIMR_ROK			BIT(0)	/*  Receive DMA OK Interrupt */
+
+#define REG_USB_SPECIAL_OPTION		0xfe55
+#define REG_USB_DMA_AGG_TO		0xfe5b
+#define REG_USB_AGG_TO			0xfe5c
+#define REG_USB_AGG_TH			0xfe5d
+
+#define REG_NORMAL_SIE_VID		0xfe60	/* 0xfe60 - 0xfe61 */
+#define REG_NORMAL_SIE_PID		0xfe62	/* 0xfe62 - 0xfe63 */
+#define REG_NORMAL_SIE_OPTIONAL		0xfe64
+#define REG_NORMAL_SIE_EP		0xfe65	/* 0xfe65 - 0xfe67 */
+#define REG_NORMAL_SIE_EP_TX		0xfe66
+#define  NORMAL_SIE_EP_TX_HIGH_MASK	0x000f
+#define  NORMAL_SIE_EP_TX_NORMAL_MASK	0x00f0
+#define  NORMAL_SIE_EP_TX_LOW_MASK	0x0f00
+
+#define REG_NORMAL_SIE_PHY		0xfe68	/* 0xfe68 - 0xfe6b */
+#define REG_NORMAL_SIE_OPTIONAL2	0xfe6c
+#define REG_NORMAL_SIE_GPS_EP		0xfe6d	/* RTL8723 only */
+#define REG_NORMAL_SIE_MAC_ADDR		0xfe70	/* 0xfe70 - 0xfe75 */
+#define REG_NORMAL_SIE_STRING		0xfe80	/* 0xfe80 - 0xfedf */
+
+/* RF6052 registers */
+#define RF6052_REG_AC			0x00
+#define RF6052_REG_IQADJ_G1		0x01
+#define RF6052_REG_IQADJ_G2		0x02
+#define RF6052_REG_BS_PA_APSET_G1_G4	0x03
+#define RF6052_REG_BS_PA_APSET_G5_G8	0x04
+#define RF6052_REG_POW_TRSW		0x05
+#define RF6052_REG_GAIN_RX		0x06
+#define RF6052_REG_GAIN_TX		0x07
+#define RF6052_REG_TXM_IDAC		0x08
+#define RF6052_REG_IPA_G		0x09
+#define RF6052_REG_TXBIAS_G		0x0a
+#define RF6052_REG_TXPA_AG		0x0b
+#define RF6052_REG_IPA_A		0x0c
+#define RF6052_REG_TXBIAS_A		0x0d
+#define RF6052_REG_BS_PA_APSET_G9_G11	0x0e
+#define RF6052_REG_BS_IQGEN		0x0f
+#define RF6052_REG_MODE1		0x10
+#define RF6052_REG_MODE2		0x11
+#define RF6052_REG_RX_AGC_HP		0x12
+#define RF6052_REG_TX_AGC		0x13
+#define RF6052_REG_BIAS			0x14
+#define RF6052_REG_IPA			0x15
+#define RF6052_REG_TXBIAS		0x16
+#define RF6052_REG_POW_ABILITY		0x17
+#define RF6052_REG_MODE_AG		0x18	/* RF channel and BW switch */
+#define  MODE_AG_CHANNEL_MASK		0x3ff
+#define  MODE_AG_CHANNEL_20MHZ		BIT(10)
+
+#define RF6052_REG_TOP			0x19
+#define RF6052_REG_RX_G1		0x1a
+#define RF6052_REG_RX_G2		0x1b
+#define RF6052_REG_RX_BB2		0x1c
+#define RF6052_REG_RX_BB1		0x1d
+#define RF6052_REG_RCK1			0x1e
+#define RF6052_REG_RCK2			0x1f
+#define RF6052_REG_TX_G1		0x20
+#define RF6052_REG_TX_G2		0x21
+#define RF6052_REG_TX_G3		0x22
+#define RF6052_REG_TX_BB1		0x23
+#define RF6052_REG_T_METER		0x24
+#define RF6052_REG_SYN_G1		0x25	/* RF TX Power control */
+#define RF6052_REG_SYN_G2		0x26	/* RF TX Power control */
+#define RF6052_REG_SYN_G3		0x27	/* RF TX Power control */
+#define RF6052_REG_SYN_G4		0x28	/* RF TX Power control */
+#define RF6052_REG_SYN_G5		0x29	/* RF TX Power control */
+#define RF6052_REG_SYN_G6		0x2a	/* RF TX Power control */
+#define RF6052_REG_SYN_G7		0x2b	/* RF TX Power control */
+#define RF6052_REG_SYN_G8		0x2c	/* RF TX Power control */
+
+#define RF6052_REG_RCK_OS		0x30	/* RF TX PA control */
+
+#define RF6052_REG_TXPA_G1		0x31	/* RF TX PA control */
+#define RF6052_REG_TXPA_G2		0x32	/* RF TX PA control */
+#define RF6052_REG_TXPA_G3		0x33	/* RF TX PA control */
-- 
2.1.0


^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-15  0:44 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
@ 2015-10-15 12:09   ` Bruno Randolf
  2015-10-15 12:16     ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Bruno Randolf @ 2015-10-15 12:09 UTC (permalink / raw)
  To: Jes.Sorensen, kvalo; +Cc: linux-wireless, Larry.Finger

Hi Jens,

I just tested your driver with a RTL8188CU rev A ("Vilros" ID 0bda:8176)
and it works well so far! I'm missing monitor mode however. Do you see
any chance to add that?

Your patch seems to be correct, but in your own git, branch
'rtl8723au-mac80211' you seem to be missing the below part:

On 10/15/2015 01:44 AM, Jes.Sorensen@redhat.com wrote:
> --- a/drivers/net/wireless/realtek/Makefile
> +++ b/drivers/net/wireless/realtek/Makefile
> @@ -5,4 +5,5 @@
>  obj-$(CONFIG_RTL8180)		+= rtl818x/
>  obj-$(CONFIG_RTL8187)		+= rtl818x/
>  obj-$(CONFIG_RTLWIFI)		+= rtlwifi/
> +obj-$(CONFIG_RTL8XXXU)		+= rtl8xxxu/

And it has that leftover in drivers/net/wireless/Makefile:

obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o

I had to add the following change to my local tree in order to be able
to build:

diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index bc44950..740fdd3 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -37,8 +37,6 @@ obj-$(CONFIG_LIBERTAS_THINFIRM)       += libertas_tf/

 obj-$(CONFIG_ADM8211)  += adm8211.o

-obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o
-
 obj-$(CONFIG_MWL8K)    += mwl8k.o

 obj-$(CONFIG_IWLWIFI)  += iwlwifi/
diff --git a/drivers/net/wireless/realtek/Makefile
b/drivers/net/wireless/realtek/Makefile
index 3489b98..9c78deb 100644
--- a/drivers/net/wireless/realtek/Makefile
+++ b/drivers/net/wireless/realtek/Makefile
@@ -5,4 +5,5 @@
 obj-$(CONFIG_RTL8180)          += rtl818x/
 obj-$(CONFIG_RTL8187)          += rtl818x/
 obj-$(CONFIG_RTLWIFI)          += rtlwifi/
+obj-$(CONFIG_RTL8XXXU)         += rtl8xxxu/

Greetings,
bruno

^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-15 12:09   ` Bruno Randolf
@ 2015-10-15 12:16     ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-10-15 12:16 UTC (permalink / raw)
  To: Bruno Randolf; +Cc: kvalo, linux-wireless, Larry.Finger

Bruno Randolf <br1@einfach.org> writes:
> Hi Jens,

Jes :)

> I just tested your driver with a RTL8188CU rev A ("Vilros" ID 0bda:8176)
> and it works well so far! I'm missing monitor mode however. Do you see
> any chance to add that?

It's on the todo list, but fairly far down the list. I am more focused
on adding support for more devices and features at this point.

> Your patch seems to be correct, but in your own git, branch
> 'rtl8723au-mac80211' you seem to be missing the below part:
>
> On 10/15/2015 01:44 AM, Jes.Sorensen@redhat.com wrote:
>> --- a/drivers/net/wireless/realtek/Makefile
>> +++ b/drivers/net/wireless/realtek/Makefile
>> @@ -5,4 +5,5 @@
>>  obj-$(CONFIG_RTL8180)		+= rtl818x/
>>  obj-$(CONFIG_RTL8187)		+= rtl818x/
>>  obj-$(CONFIG_RTLWIFI)		+= rtlwifi/
>> +obj-$(CONFIG_RTL8XXXU)		+= rtl8xxxu/
>
> And it has that leftover in drivers/net/wireless/Makefile:
>
> obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o
>
> I had to add the following change to my local tree in order to be able
> to build:
>
> diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
> index bc44950..740fdd3 100644
> --- a/drivers/net/wireless/Makefile
> +++ b/drivers/net/wireless/Makefile
> @@ -37,8 +37,6 @@ obj-$(CONFIG_LIBERTAS_THINFIRM)       += libertas_tf/
>
>  obj-$(CONFIG_ADM8211)  += adm8211.o
>
> -obj-$(CONFIG_RTL8XXXU) += rtl8xxxu.o
> -
>  obj-$(CONFIG_MWL8K)    += mwl8k.o
>
>  obj-$(CONFIG_IWLWIFI)  += iwlwifi/
> diff --git a/drivers/net/wireless/realtek/Makefile
> b/drivers/net/wireless/realtek/Makefile
> index 3489b98..9c78deb 100644
> --- a/drivers/net/wireless/realtek/Makefile
> +++ b/drivers/net/wireless/realtek/Makefile
> @@ -5,4 +5,5 @@
>  obj-$(CONFIG_RTL8180)          += rtl818x/
>  obj-$(CONFIG_RTL8187)          += rtl818x/
>  obj-$(CONFIG_RTLWIFI)          += rtlwifi/
> +obj-$(CONFIG_RTL8XXXU)         += rtl8xxxu/

Thanks, I already fixed this, but I may have forgotten to git push
it. Let me fix that.

Thanks for testing, I am pleased to hear it works well for you!

Cheers,
Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
@ 2015-10-23 13:07 Xose Vazquez Perez
  2015-10-23 14:00 ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Xose Vazquez Perez @ 2015-10-23 13:07 UTC (permalink / raw)
  To: linux-wireless, Kalle Valo, Jes Sorensen, Larry Finger

Jes Sorensen wrote:

> This is an alternate driver for a number of Realtek WiFi USB devices,
> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
> It was written from scratch utilizing the Linux mac80211 stack.
>[...]
>+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
>[...]
>+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff, 0xff, 0xff),
>[...]

This device was duplicated. Delete one of them.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-23 13:07 [PATCH 1/1] New driver: rtl8xxxu (mac80211) Xose Vazquez Perez
@ 2015-10-23 14:00 ` Jes Sorensen
  2015-10-23 16:09   ` Jes Sorensen
  0 siblings, 1 reply; 68+ messages in thread
From: Jes Sorensen @ 2015-10-23 14:00 UTC (permalink / raw)
  To: Xose Vazquez Perez; +Cc: linux-wireless, Kalle Valo, Larry Finger

Xose Vazquez Perez <xose.vazquez@gmail.com> writes:
> Jes Sorensen wrote:
>
>> This is an alternate driver for a number of Realtek WiFi USB devices,
>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>> It was written from scratch utilizing the Linux mac80211 stack.
>>[...]
>>+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff,
>> 0xff, 0xff),
>>[...]
>>+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff,
>> 0xff, 0xff),
>>[...]
>
> This device was duplicated. Delete one of them.

You could just have sent me a patch instead of this.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH 1/1] New driver: rtl8xxxu (mac80211)
  2015-10-23 14:00 ` Jes Sorensen
@ 2015-10-23 16:09   ` Jes Sorensen
  0 siblings, 0 replies; 68+ messages in thread
From: Jes Sorensen @ 2015-10-23 16:09 UTC (permalink / raw)
  To: Xose Vazquez Perez; +Cc: linux-wireless, Kalle Valo, Larry Finger

Jes Sorensen <Jes.Sorensen@redhat.com> writes:
> Xose Vazquez Perez <xose.vazquez@gmail.com> writes:
>> Jes Sorensen wrote:
>>
>>> This is an alternate driver for a number of Realtek WiFi USB devices,
>>> including RTL8723AU, RTL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU.
>>> It was written from scratch utilizing the Linux mac80211 stack.
>>>[...]
>>>+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff,
>>> 0xff, 0xff),
>>>[...]
>>>+{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x317f, 0xff,
>>> 0xff, 0xff),
>>>[...]
>>
>> This device was duplicated. Delete one of them.
>
> You could just have sent me a patch instead of this.

I've fixed this in my devel branch.

Jes

^ permalink raw reply	[flat|nested] 68+ messages in thread

end of thread, other threads:[~2015-10-23 16:09 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-08-30 21:02 [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
2015-08-30 21:02 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
2015-09-06 14:59   ` Kalle Valo
2015-09-06 17:06     ` Larry Finger
2015-09-07  1:41       ` Jes Sorensen
2015-09-07  1:40     ` Jes Sorensen
2015-09-07 13:20       ` Kalle Valo
2015-09-07 21:08         ` Jes Sorensen
2015-09-06 14:43 ` [PATCH v2 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Kalle Valo
2015-09-06 17:03   ` Larry Finger
2015-09-07  9:06     ` Kalle Valo
2015-09-07 15:35       ` Larry Finger
2015-09-08 21:04         ` Jes Sorensen
2015-09-08 21:13       ` Jes Sorensen
2015-09-08 21:01     ` Jes Sorensen
2015-09-09 10:51       ` Bruno Randolf
2015-09-07  1:45   ` Jes Sorensen
2015-09-07  4:24     ` Jes Sorensen
2015-09-07  8:53       ` Kalle Valo
2015-09-07  9:17     ` Kalle Valo
2015-09-08 21:24       ` Jes Sorensen
  -- strict thread matches above, loose matches on Subject: below --
2015-10-23 13:07 [PATCH 1/1] New driver: rtl8xxxu (mac80211) Xose Vazquez Perez
2015-10-23 14:00 ` Jes Sorensen
2015-10-23 16:09   ` Jes Sorensen
2015-10-15  0:44 [PATCH v3 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
2015-10-15  0:44 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
2015-10-15 12:09   ` Bruno Randolf
2015-10-15 12:16     ` Jes Sorensen
2015-08-29 21:18 [PATCH 0/1] rtl8xxxu (mac80211) driver for rtl8188[cr]u/rtl8192cu/rtl8723au Jes.Sorensen
2015-08-29 21:18 ` [PATCH 1/1] New driver: rtl8xxxu (mac80211) Jes.Sorensen
2015-08-30  4:42   ` Larry Finger
2015-08-30 18:41     ` Jes Sorensen
2015-08-30 21:02       ` Jes Sorensen
2015-08-30 23:51       ` Larry Finger
2015-08-31  2:39         ` Jes Sorensen
2015-08-31 15:45           ` Larry Finger
2015-08-31 23:43             ` Jes Sorensen
2015-09-01  0:16               ` Larry Finger
2015-09-01  4:54                 ` Jes Sorensen
2015-09-01  5:17                   ` Larry Finger
2015-09-01  5:26                     ` Jes Sorensen
2015-08-31  1:06       ` Joe Perches
2015-08-31 13:11         ` Jes Sorensen
2015-08-31  8:19       ` Johannes Berg
2015-08-31 14:48   ` Johannes Berg
2015-08-31 23:42     ` Jes Sorensen
2015-09-01 15:07       ` Johannes Berg
2015-09-03  1:59         ` Jes Sorensen
2015-09-03  2:39           ` Jes Sorensen
2015-09-03 10:17             ` Johannes Berg
2015-09-04 18:24               ` Jes Sorensen
2015-09-04 18:25                 ` Johannes Berg
2015-09-05  4:02                 ` Sujith Manoharan
2015-09-17 16:46                   ` Johannes Berg
2015-10-05 18:49                     ` Jes Sorensen
2015-10-05 18:56                       ` Johannes Berg
2015-10-05 19:04                         ` Jes Sorensen
2015-10-05 19:12                           ` Johannes Berg
2015-10-05 19:19                             ` Jes Sorensen
2015-10-05 19:20                               ` Johannes Berg
2015-10-05 19:53                                 ` Jes Sorensen
2015-09-03 10:17           ` Johannes Berg
2015-09-04 17:48             ` Jes Sorensen
2015-09-04 18:02               ` Johannes Berg
2015-10-08 16:23   ` Jakub Sitnicki
2015-10-08 19:09     ` Jes Sorensen
2015-10-08 20:33       ` Stefan Lippers-Hollmann
2015-10-08 21:06         ` Jes Sorensen
2015-10-08 21:03       ` Jes Sorensen
2015-10-10  4:17       ` Taehee Yoo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).